【译】Java String intern()对程序性能有哪些影响?转载
java.lang.String#intern()是 Java 中一个有趣的函数。在正确的地方使用时,它可以通过消除程序中的重复字符串来减少应用程序的整体内存消耗。在这篇文章中,让我们讨论java.lang.String#intern()
在应用程序中使用函数对性能的影响。
Intern() 函数演示
为了研究该intern()
方法的性能行为,我们创建了这两个简单的程序:
public class InternDemo {
private static List<String> datas = new ArrayList<>(10_000_000);
public static void main(String args[]) throws Exception {
BufferedReader reader = new BufferedReader(new FileReader("C:\\workspace\\random-data.txt"));
String data = reader.readLine();
while (data != null) {
data = reader.readLine().intern();
datas.add(data);
}
reader.close();
}
}
public class NoInternDemo {
private static List<String> datas = new ArrayList<>(10_000_000);
public static void main(String args[]) throws Exception {
BufferedReader reader = new BufferedReader(new FileReader("C:\\workspace\\random-data.txt"));
String data = reader.readLine();
while (data != null) {
data = reader.readLine();
datas.add(data);
}
reader.close();
}
}
在进一步阅读之前,先看看上述源代码。
这是一个简单的程序。如果您注意到,“ InternDemo ”程序一次从“ random-data.txtintern()
”中读取每一行,然后对读取的数据进行调用操作。
最后将 intern() 函数返回的字符串添加到'datas' ArrayList。'NoInternDemo'程序也做同样的事情,唯一的区别是'NoInternDemo'不调用'intern() ' 操作和' InternDemo ' 调用' intern() ' 操作。
这里你还需要了解“ random-data.txt ”的内容。该文件包含 1000 万个 UUID(通用唯一标识符)字符串。尽管该文件中有 1000 万个 UUID 字符串,但它们之间存在大量重复。基本上,只有 10 个唯一的 UUID,在这个文件中插入了 1000 万次。数据的结构有意使该文件中存在大量重复字符串。您可以点击这里下载我们用于此实验的“random-data.txt”文件。
对内存的影响
我们执行了这两个程序。在程序退出之前,我们从它们那里捕获了堆转储。堆转储作为内存 的快照,其中包含有关驻留在内存中的所有对象信息。我们通过堆转储分析工具HeapHero研究了堆转储。以下是此工具生成的实时报告:
下表总结了这两个程序之间的区别:
InternDemo | NoInternDemo | |
总大小 | 38.37MB | 1.08GB |
对象计数 | 4,184 | 20,004,164 |
类数 | 456 | 456 |
你可以注意到,“InternDemo”只有 4k+ 个对象,仅消耗 38.37MB,而“NoInternDemo”有 2000 万个以上对象,消耗 1.08GB 内存。基本上'NoInternDemo'消耗的内存是'InternDemo'的28 倍。该演示清楚地说明了内存优化是通过intern()函数实现的。
重复字符串影响
HeapHero 工具在其报告中指出由于低效的编程实践而浪费了多少内存。我们注意到“InternDemo”没有浪费任何内存,而“NoInternDemo”由于低效的编程实践而浪费了 1.04GB(即 97%)的内存。在这 97% 的内存浪费中,96.5% 的浪费是由于重复字符串造成的。
HeapHero 报告的 InternDemo 内存浪费
HeapHero 报告的 NoInternDemo 内存浪费
该工具还指出,以下是内存中存在的重复字符串。基本上,这 10 个字符串是 random-data.txt 文件中存在的 10 个唯一 UUID。由于重复,每个字符串都浪费了 106MB 的内存。如果使用了intern()操作,那么这种内存浪费是可以避免的。
HeapHero 报告的 NoInternDemo 中存在的重复字符串
响应时间影响
我们多次执行“InternDemo”和“ NoInternDemo”程序。下图显示了这两个程序的平均响应时间:
InternDemo | NoInternDemo |
2042 毫秒 | 1164 毫秒 |
基本上,“ InternDemo”比“NoInternDemo ”慢 75%。这只是因为'InternDemo'必须对 1000 万条记录的 String Intern中的所有对象调用string.equals()方法。因此它消耗更多的CPU和时间。因此,“InternDemo”的响应时间比“ NoInternDemo ”慢。难怪人们说:“天下没有免费的午餐”。从内存的角度来看, “ InternDemo”表现出色。从 CPU/响应时间的角度来看, “NoInternDemo”具有很高的性能。
注意: intern() 函数的性能影响在很大程度上取决于您的应用程序处理的数据。在上面的示例中,存在大量重复字符串,因此你会看到内存利用率大幅降低和响应时间激增。在所有应用程序中,这可能不是相同的行为。在您的应用程序中使用 intern() 函数之前,你必须执行适当的测试。