这也是一篇有趣的问答。
扫码关注《Java学研大本营》,加入读者群,分享更多精彩
intern()是java.lang.String对象中一个有趣的函数。intern()函数从应用程序中消除重复的字符串对象,并有可能减少应用程序的整体内存消耗。在这篇文章中,让我们更多地了解这个intern()函数。
1. String intern() 函数是如何工作的?
在 Java 堆内存中,维护了一个字符串对象池。当您在 String 对象上调用intern()函数时,JVM 将检查该字符串对象是否已存在于池中。如果存在,则将相同的对象返回给调用者。如果字符串对象不存在,则将该字符串对象添加到池中,并将新添加的字符串对象返回给调用者。
通过示例和图片学习总是很容易。我们开始做吧。让我们看看下面的代码片段:
1: String s1 = new String("yCrash").intern();
2: String s2 = new String("yCrash").intern();
图:初始启动时的 JVM 堆内存
您的应用程序创建的所有对象都存储在 JVM 的堆内存中。这个 JVM 堆内存内部有一个字符串实习池。最初启动程序时,JVM 的堆内存将没有字符串对象。
图:'String s1 = new String(“yCrash”).intern();' 时的 JVM 堆内存 被执行
当第一条语句' String s1 = new String(“yCrash”).intern(); ' 执行后,JVM 会检查“ yCrash ”字符串对象是否存在于 intern 字符串池中。由于它不存在,这个“ yCrash ”字符串将被添加到实习生字符串池中,并且这个新创建的 String 对象的引用将返回给 s1。
图:'String s2 = new String(“yCrash”).intern();' 时的 JVM 堆内存 被执行
当第二条语句' String s2 = new String(“yCrash”).intern(); ' 执行后,JVM 将再次检查“ yCrash ”字符串对象是否存在于实习字符串池中。这一次,“ yCrash ”字符串对象出现在实习生字符串池中,因为它是在执行语句 #1 时添加的。现在这个旧字符串对象的引用将返回给 s2。现在 s1 和 s2 都将指向同一个“ yCrash ”字符串对象。因此,在语句#2 中创建的重复字符串对象“ yCrash ”将被丢弃。
2. 没有 intern() 函数的 String 是如何工作的?
1: String s3 = new String("yCrash");
2: String s4 = new String("yCrash");
图:'String s3 = new String(“yCrash”);' 时的 JVM 堆内存 被执行
当第一条语句'String s3 = new String(“yCrash”);' 执行时,JVM 会将“yCrash”字符串对象添加到堆内存中,而不是在实习生字符串池中。
图:'String s4 = new String(“yCrash”);' 时的 JVM 堆内存 被执行
当第二条语句'String s4 = new String(“yCrash”);' 执行后,JVM 会在堆内存中创建一个新的“yCrash”字符串对象。因此,将在内存中创建重复的“yCrash” 。如果您的应用程序在没有调用 intern()的情况下创建 n 个“yCrash”对象,则将在内存中创建n 个“yCrash”字符串对象。这将导致大量的内存浪费。
3. intern() 和 == 是如何工作的?
由于 s1 和 s2 指向同一个“yCrash”字符串对象,当您在 s1 和 s2 之间调用'=='操作时,如下所示,您将得到 'true' 作为结果。
// true will be printed
System.out.println(s1 == s2);
由于 s3 和 s4 指向两个不同的“yCrash”字符串对象,当您在 s3 和 s4 之间调用'=='操作时,如下所示,您将得到 'false' 作为结果。
// false will be printed
System.out.println(s3 == s4);
4、Intern String pool存放在哪个JVM内存区域?
JVM 内存有以下区域:
堆区域(即年轻代+老一代)
元空间
其他区域
要了解这些 JVM 内存区域,您可以参考此视频剪辑(https://www.youtube.com/watch?v=uJLOlCuOR4k)。在 Java 1 到 6 的早期版本中,字符串实习池存储在 Perm Generation 中。从 java 7 开始,String intern pool 存储在 JVM 的堆内存中。为了证实这一点,我们进行了这个简单的实验(https://blog.ycrash.io/2022/08/03/in-which-region-intern-strings-are-stored/)。
5.使用intern()还是-XX:+UseStringDeduplication更好?
当您在应用程序启动期间传递 ' -XX:+UseStringDeduplication ' JVM 参数时,JVM 将尝试消除重复字符串作为垃圾收集过程的一部分。在垃圾收集过程中,JVM 检查内存中的所有对象。作为此过程的一部分,它会尝试识别其中的重复字符串并尝试消除它们。但是,使用'-XX:+UseStringDeduplication ' JVM 参数有一定的限制,例如它只能与 G1 GC 算法一起使用,并且只能在长寿命的字符串对象上消除重复,...要了解有关此参数的更多信息,您可以参考到这个帖子(https://blog.gceasy.io/2018/12/23/usestringdeduplication/)。这是一个关于一个主要应用程序的有趣案例研究(https://blog.gceasy.io/2018/07/17/disappointing-story-on-memory-optimization/),它试图使用'-XX:+UseStringDeduplication' JVM 参数。
另一方面,intern()函数可以与任何 GC 算法一起使用,也可以用于短期/长期对象。但是,intern() 函数对应用程序响应时间的影响可能超过'-XX:+UseStringDeduplication',有关更多详细信息,请参阅此博客文章(https://blog.ycrash.io/2022/08/11/java-string-intern-performance-impact/)。
6、intern()函数对性能有什么影响?
根据这篇文章,您可能已经了解到,在字符串对象上调用 intern ()函数有可能从内存中消除重复的字符串,从而降低整体内存利用率。但是,它可能会影响响应时间和 CPU 利用率。要了解使用intern()函数对性能的影响,您可以参考这篇文章(https://blog.ycrash.io/2022/08/11/java-string-intern-performance-impact/)。
视频:
参考文章: https://medium.com/@RamLakshmanan/java-string-intern-interesting-q-a-50f7d316f853
推荐书单
《HTML5+CSS3+JavaScript从入门到精通》
购买链接:https://item.jd.com/12659883.html
《HTML5+CSS3+JavaScript从入门到精通(微视频精编版 套装共2本)/软件开发微视频讲堂》内容浅显易懂,实例丰富,详细介绍了HTML5+CSS3+JavaScript开发需要掌握的各类实战知识。
全书分为两册:核心技术分册和强化训练分册。核心技术分册共17章,包括HTML,基础、文本、图像和超链接、CSS3概述、CSS3高级应用、表格与标签、列表、表单、多媒体、HTML5新特性、JavaScript基础、绘制图形、文件与拖放、JavaScnpt对象编程、响应式网页设计、响应式组件、课程设计——游戏公园等内容。通过学习,读者可快速开发一些中小型应用程序。强化训练分册共15章,通过大量源于实际生活的趣味案例,强化上机实践,拓展和提升软件开发中对实际问题的分析与解决能力。
精彩回顾
扫码关注《Java学研大本营》,加入读者群,分享更多精彩