性能文章>【译】Java String intern()对程序性能有哪些影响?>

【译】Java String intern()对程序性能有哪些影响?转载

2月前
204923

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研究了堆转储。以下是此工具生成的实时报告:

  1.  InternDemo 堆分析报告 
  2. NoInternDemo 堆分析报告 

 下表总结了这两个程序之间的区别:

                                                                                 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 报告的 InternDemo 内存浪费

图:HeapHero 报告的 NoInternDemo 内存浪费

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() 函数之前,你必须执行适当的测试。

点赞收藏
金色梦想

终身学习。

请先登录,查看2条精彩评论吧
快去登录吧,你将获得
  • 浏览更多精彩评论
  • 和开发者讨论交流,共同进步

为你推荐

没有二十年功力,写不出Thread.sleep(0)这一行“看似无用”的代码!

没有二十年功力,写不出Thread.sleep(0)这一行“看似无用”的代码!

技术分享 | 幽灵攻击与编译器中的消减方法介绍

技术分享 | 幽灵攻击与编译器中的消减方法介绍

【全网首发】微服务10:系统服务熔断、限流

【全网首发】微服务10:系统服务熔断、限流

【全网首发】MQ-消息堆积-JDK Bug导致线程阻塞案例分析

【全网首发】MQ-消息堆积-JDK Bug导致线程阻塞案例分析

【全网首发】不经意的两行代码把CPU使用率干到了90%+

【全网首发】不经意的两行代码把CPU使用率干到了90%+

如何修改 Nginx 源码实现 worker 进程隔离

如何修改 Nginx 源码实现 worker 进程隔离

3
2