Java 8 的字符串去重特性

2023-11-23

Since String在 Java 中(像其他语言一样)会消耗大量内存,因为每个字符消耗两个字节,Java 8 引入了一个新功能,称为字符串去重它利用了这样一个事实:字符数组是字符串和最终的内部数组,因此 JVM 可以对它们进行处理。

我读过了这个例子到目前为止,但由于我不是专业的 java 程序员,所以我很难理解这个概念。

它是这样说的:

已经考虑了各种字符串复制策略,但是 现在实施的方法遵循以下方法:每当 垃圾收集器访问 String 对象并记录下字符 数组。它获取它们的哈希值并将其与弱值一起存储 对数组的引用。一旦它找到另一个具有 相同的哈希码,它逐个字符地比较它们。如果它们匹配为 好吧,一个 String 将被修改并指向 char 数组 第二个字符串。然后第一个字符数组不再被引用 不再存在并且可以被垃圾收集。

整个过程当然会带来一些开销,但是是受控制的 通过严格的限制。例如,如果未找到字符串 重复一段时间就不再检查了。

我的第一个问题,

由于最近在 Java 8 update 20 中添加了该主题,因此仍然缺乏资源,这里有人可以分享一些关于它如何帮助减少内存消耗的实际示例吗?String在爪哇?

Edit:

上面的链接说,

一旦它找到另一个具有相同哈希码的字符串 逐个字符地比较它们

我的第二个问题,

如果哈希码为两个String是相同的Strings已经一样了,那为什么要比较呢char by char一旦发现两人String有相同的哈希码吗?


@assylias 答案基本上告诉你它是如何工作的,并且是非常好的答案。我已经使用字符串重复数据删除测试了生产应用程序并得到了一些结果。该网络应用程序大量使用字符串,因此我认为其优势非常明显。

要启用字符串重复数据删除,您必须添加以下 JVM 参数(您至少需要 Java 8u20):

-XX:+UseG1GC -XX:+UseStringDeduplication -XX:+PrintStringDeduplicationStatistics

最后一项是可选的,但正如名称所示,它会显示字符串重复数据删除统计信息。这是我的:

[GC concurrent-string-deduplication, 2893.3K->2672.0B(2890.7K), avg 97.3%, 0.0175148 secs]
   [Last Exec: 0.0175148 secs, Idle: 3.2029081 secs, Blocked: 0/0.0000000 secs]
      [Inspected:           96613]
         [Skipped:              0(  0.0%)]
         [Hashed:           96598(100.0%)]
         [Known:                2(  0.0%)]
         [New:              96611(100.0%)   2893.3K]
      [Deduplicated:        96536( 99.9%)   2890.7K( 99.9%)]
         [Young:                0(  0.0%)      0.0B(  0.0%)]
         [Old:              96536(100.0%)   2890.7K(100.0%)]
   [Total Exec: 452/7.6109490 secs, Idle: 452/776.3032184 secs, Blocked: 11/0.0258406 secs]
      [Inspected:        27108398]
         [Skipped:              0(  0.0%)]
         [Hashed:        26828486( 99.0%)]
         [Known:            19025(  0.1%)]
         [New:           27089373( 99.9%)    823.9M]
      [Deduplicated:     26853964( 99.1%)    801.6M( 97.3%)]
         [Young:             4732(  0.0%)    171.3K(  0.0%)]
         [Old:           26849232(100.0%)    801.4M(100.0%)]
   [Table]
      [Memory Usage: 2834.7K]
      [Size: 65536, Min: 1024, Max: 16777216]
      [Entries: 98687, Load: 150.6%, Cached: 415, Added: 252375, Removed: 153688]
      [Resize Count: 6, Shrink Threshold: 43690(66.7%), Grow Threshold: 131072(200.0%)]
      [Rehash Count: 0, Rehash Threshold: 120, Hash Seed: 0x0]
      [Age Threshold: 3]
   [Queue]
      [Dropped: 0]

这些是运行应用程序 10 分钟后的结果。如您所见,字符串去重已执行452次和“重复数据删除”801.6 MB字符串。检查字符串重复数据删除27 000 000字符串。当我将使用标准并行 GC 的 Java 7 与使用 G1 GC 的 Java 8u20 的内存消耗进行比较并启用字符串重复数据删除时,堆大约下降了50%:

Java 7 并行 GC

Java 7 Parallel GC

带有字符串重复数据删除功能的 Java 8 G1 GC

Java 8 G1 GC with String Deduplication

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java 8 的字符串去重特性 的相关文章

随机推荐