使用G1 GC,降低内存消耗20%

时间:2022-06-04
本文章向大家介绍使用G1 GC,降低内存消耗20%,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

由于Web服务API调用(例如JSON,REST,SOAP,...),外部数据源调用(SQL,从DB拿到的数据,...),文本解析,文本构建等等,如今的Java应用程序会执行大量的字符串操作。 因此,字符串对象可以轻松占用至少30%的内存。 显然,这些String对象的大部分都是重复的。 由于字符串重复,浪费了大量内存。 因此,为了优化重复字符串对象浪费的内存,JEP 192中增加了对重复字符串的优化。

JEP 192 :G1的String去重

当我们使用G1 GC时,它会从内存中删除垃圾对象。 它还从内存中删除重复的字符串对象,叫做string deduplication(字符串去重)。 而且只需要通过传递以下JVM参数就可以激活此功能:

-XX:+UseG1GC -XX:+UseStringDeduplication

Note 1:要想使用此功能,你需要把你的Java升级到Java 8 update 20以及往后的版本。

Note 2:“ -XX:+UseStringDeduplication” 参数是运行在G1之上的,所以你需要在G1下使用此参数才会生效。

例子

接下来用一个简单的程序来验证此功能。

public class StringDeduplicationExample {
    public static List<String> myStrings = new ArrayList();
    public static void main(String[] args) throws Exception {
        for (int counter = 0; counter < 200; ++counter) {
            for (int secondCounter = 0; secondCounter < 1000; ++secondCounter) {
                //添加一千次
                myStrings.add(("Hello World-" + counter));
            }
            System.out.println("Hello World-" + counter + " 被添加了1000次");
        }
    }
}

这个程序基本逻辑就是创造了一堆重复的字符串:

1000个 “Hello World-0” 字符串实例

1000个 “Hello World-1” 字符串实例

1000个 “Hello World-2” 字符串实例

...

...

...

1000个 “Hello World-199” 字符串实例

然后分别用两个不同的JVM参数来运行这个程序。

Run#1

本次运行我们使用 ‘-XX:+ UseStringDeduplication’ 来运行程序。即:

-Xmx20M -XX:+UseG1GC -XX:+UseStringDeduplication

Run#2

第二次运行我们去掉 ‘-XX:+ UseStringDeduplication’ 来运行程序。即:

-Xmx20M -XX:+UseG1G

在两次运行期间,我们捕获了heap dump并通过堆分析工具HeapHero.io分析了dump文件。 HeapHero.io可以检测由于各种低效的编程实践而浪费的内存量,包括由于重复字符串而浪费掉的内存量。

以下是由HeapHero.io生成的报告:

第一次带参数的运行分析报告: http://heaphero.io/heap-s3-progress.jsp?p=YXJjaGl2ZWQvMjAxOC8wNC8xOS8tLXN5c3Byb3BlcnR5LTIwbWIuaHByb2YtMTktNTAtMy0t 第二次不带参数的运行分析报告: http://heaphero.io/heap-s3-progress.jsp?p=YXJjaGl2ZWQvMjAxOC8wNC8xOS8tLW5vc3lzcHJvcGVydHktMjBtYi5ocHJvZi0xOS01MS00LS0=

以下是报告中的一些指标:

Run#1 带去重参数:

Run#2 不带去重参数:

报告中的几个有趣的指标:

即使执行了相同的代码,在Run #1(传递了参数'-XX:+ UseStringDeduplication'),我们可以看到总堆大小为7.94mb,而在Run #2中(没有传递去重参数'-XX:+ UseStringDeduplication' ),整个堆大小有了相当大的增加 - 15.89mb。

尽管在两次运行(206092)中都有相同数量的字符串对象,但由于Run #1中的重复字符串而浪费的内存量为5.6mb,而在Run #2中则多达13.81mb。

由于“-XX:+ UseStringDeduplication”参数使内存消耗大大减少,它可以从应用程序中清除大量重复的字符串。因此,鼓励大家多使用“-XX:+ UseG1GC -XX:+ UseStringDeduplication”,这样可以减少由于重复字符串而引起的内存浪费。这样做有可能能够降低应用程序的整体内存占用量。