JVM消除重复自负参数-XX:+UseStringDeduplication的优缺点 - JAXenter

栏目: Java · 发布时间: 7年前

内容简介:什么是重复的字符串?25%的Java应用程序内存中填充了字符串,其中13.5%是重复的字符串。在本文中,Ram Lakshmanan讨论了为什么有这么多重复的字符串,常见的模式是什么,以及如何处理它。让我从一篇有趣的统计数据开始本文(基于JDK开发团队的研究):您可以使用

什么是重复的字符串?25%的 Java 应用程序内存中填充了字符串,其中13.5%是重复的字符串。在本文中,Ram Lakshmanan讨论了为什么有这么多重复的字符串,常见的模式是什么,以及如何处理它。

让我从一篇有趣的统计数据开始本文(基于JDK开发团队的研究):

+ 25%的Java应用程序内存中充满了字符串。
+ 13.5%是Java应用程序中的重复字符串。
+ 平均字符串长度为45个字符。

您可以使用 HeapHero之类的 工具,它可以报告由于重复字符串和其他低效编程实践而浪费了多少内存。

什么是重复的字符串?

首先,让我们了解重复字符串的含义。请看下面的代码片段:

String string1 = <b>new</b> String(<font>"Hello World"</font><font>);
String string2 = <b>new</b> String(</font><font>"Hello World"</font><font>);
</font>

在上面的代码中有两个字符串对象string1和string2它们具有相同的内容,即“Hello World”,但它们存储在两个不同的对象中。当你执行string1.equals(string2)时,它将返回'true',但'string1 == string2'将返回'false'。这就是我们所说的重复字符串。

为什么有这么多重复的字符串?

应用程序最终会出现大量重复字符串的原因有多种。在本节中,我们将回顾两种最常见的模式:

1. 开发人员为每个请求创建新的字符串对象,而不是引用/重用“public static final string literal”。上面的示例可以使用字符串文字模式进行最佳编写:

<b>public</b> <b>static</b> <b>final</b> String HELLO_WORLD = <font>"Hello World"</font><font>;
String string1 = HELLO_WORLD;
String string2 = HELLO_WORLD;
</font>

2.假设您正在构建银行/电子商务应用程序。您正在为数据库中的每个交易记录存储货币(即“USD”,“EUR”,“INR”,......)。现在说客户登录您的应用程序,他正在查看他的交易历史页面。现在,您的应用程序将最终从数据库中读取与此客户相关的所有事务。假设这个客户住在美国(那么大部分(如果不是全部)他的交易将以美元为单位)。由于每个交易记录都有货币,因此您的应用程序最终会为从数据库读取的每个交易记录创建一个“USD”字符串对象。如果这个客户有成千上万的交易,你最终会在内存中创建数千个重复的'USD'字符串对象,这对于这一个客户来说也是如此。

同样,您的应用程序可能会多次从数据库中读取多个列(客户名称,地址,州,国家/地区,帐号,ID,......)。它们之间可能存在重复。您的应用程序使用外部应用程序读取和写入XML / JSON,它操纵了很多字符串。所有这些操作都可以/将创建重复的字符串。

自从JDK团队组建开始(20世纪90年代中期)以来,这个问题一直被人们认可,因此到目前为止已经提出了多种解决方案。此解决方案列表的最新成员是'-XX:+ UseStringDeduplication'

-XX:+UseStringDeduplication

尝试消除重复字符串的最小努力是传递'-XX:+ UseStringDeduplication'JVM参数。在应用程序启动期间传递此JVM参数时,JVM将尝试在垃圾收集过程中消除重复的字符串。在垃圾收集过程中,JVM会检查内存中的所有对象,因此作为该过程的一部分,它会尝试识别它们中的重复字符串并尝试消除它。

是否意味着如果你只是传递'-XX:+ UseStringDeduplication'JVM参数你能立即节省13.5%的内存吗?:-)听起来很容易,对吧?我们希望这很容易。但是这个'-XX:+ UseStringDeduplication'解决方案有一些问题。我们来讨论一下:

1.仅适用于G1 GC算法

有几种垃圾收集算法(串行,并行,CMS,G1,......)。'-XX:+ UseStringDeduplication'仅在您使用G1 GC算法时有效。因此,如果您使用其他GC算法,则需要切换到G1 GC算法以使用'-XX:+ UseStringDeduplication'。

2.仅适用于长寿命对象

'-XX:+ UseStringDeduplication'消除了较长时间内存在的重复字符串。它们不会消除短期字符串对象中的重复字符串。如果对象是短暂的,它们将很快消失,那么花费资源消除它们中的重复字符串的重点是什么。以下是对主要Java Web应用程序进行的真实案例研究,当使用'-XX:+ UseStringDeduplication'时,该应用程序没有显示任何内存缓解。但是,如果您的应用程序有很多缓存,那么'-XX:+ UseStringDeduplication'可能是有价值的(因为缓存对象通常往往是长期存在的对象)。

3. -XX:StringDeduplicationAgeThreshold

默认情况下,如果字符串在3次GC运行中幸存,则符合重复数据删除的条件。可以通过传递'-XX:StringDeduplicationAgeThreshold'来更改3次这个参数。例:

-XX:StringDeduplicationAgeThreshold=6

4.对GC暂停时间的影响

由于在重复垃圾收集期间执行字符串重复数据删除,因此可能会影响GC暂停时间。但是,假设足够高的重复数据删除成功率将平衡大部分或全部这种影响,因为重复数据删除可以减少GC暂停的其他阶段所需的工作量(例如减少撤离的对象数量)以及减少GC频率(由于堆上的压力减小)。

要分析GC暂停时间影响,您可以考虑使用 GCeasy等 工具。

5.只替换底层char []

java.lang.String类有两个字段:

<b>private</b> <b>final</b> <b>char</b>[] value
<b>private</b> <b>int</b> hash

'-XX:+ UseStringDeduplication'不会消除重复的字符串对象本身。它只替换了底层的char []。对String对象进行重复数据删除在概念上只是对value字段的重新赋值,即aString.value = anotherString.value。

每个字符串对象至少需要24个字节(字符串对象的确切大小取决于JVM配置,但最少24个字节)。因此,如果存在大量短重复字符串,则此功能可以节省更少的内存。

6. Java 8 update 20

'-XX:+ UseStringDeduplication'功能仅受Java 8 update 20中支持。因此,如果您在任何旧版本的Java上运行,您将无法使用此功能。

7. -XX:+ PrintStringDeduplicationStatistics

如果您希望查看字符串重复数据删除统计信息,例如运行所花费的时间,撤出的重复字符串数量,您获得了多少节省,您可以传递'-XX:+ PrintStringDeduplicationStatistics'JVM参数。在错误控制台中将打印统计信息。

结论

如果您的应用程序使用G1 GC并运行在Java 8更新20之上的版本,您可以考虑启用'-XX:+ UseStringDeduplication'。您可能会获得富有成效的结果,尤其是在长寿命对象中存在大量重复字符串的情况下。但是,在生产环境中启用此参数之前,请进行全面测试。


以上所述就是小编给大家介绍的《JVM消除重复自负参数-XX:+UseStringDeduplication的优缺点 - JAXenter》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。

老二非死不可

老二非死不可

方三文 / 机械工业出版社 / 2013-12 / 39.00

关于投资 价值投资者为啥都买茅台? 怎样识别好公司与坏公司? 做空者真的罪大恶极吗? 国际板对A股会有什么影响? 波段操作,止损割肉到底靠不靠谱? IPO真的是A股萎靡不振的罪魁祸首吗? 关于商业 搜狐的再造战略有戏吗? 新浪如何焕发第二春? 百度的敌人为什么是它自己? 我为什么比巴菲特早两年投资比亚迪? 民族品牌这张牌还靠谱......一起来看看 《老二非死不可》 这本书的介绍吧!

在线进制转换器
在线进制转换器

各进制数互转换器

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具