Skip to content

jieefeng/G1

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

15 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

一丶测试程序

每秒进行一百次的操作(可能为生成对象或者释放对象 巨大对象的操作次数会少于正常对象)

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class G1GCDemo2 {
    private static final List<byte[]> longLivedObjects = new ArrayList<>();
    private static final int NUM_LARGE_OBJECTS = 50;
    private static final int LARGE_OBJECT_SIZE = 2048 * 1024; // 2 MB

    public static void main(String[] args) throws Exception {

        Random random = new Random();

        List<byte[]> objects = new ArrayList<>();

        long start = System.currentTimeMillis();

        long end = start + 60 * 1000; // 运行1分钟

        // 分配一些长生命周期的大对象
        for (int i = 0; i < NUM_LARGE_OBJECTS; i++) {
            longLivedObjects.add(new byte[LARGE_OBJECT_SIZE]);
        }

        while (System.currentTimeMillis() < end) {
            if (random.nextBoolean()) {
                int r = random.nextInt(3);
                // 分配新的对象
                if(r != 1){
                    // 分配大对象
                    if(random.nextBoolean()){
                        longLivedObjects.add(new byte[LARGE_OBJECT_SIZE]);
                    } else {
                        // 释放一些对象
                        longLivedObjects.remove(random.nextInt(longLivedObjects.size()));
                    }
                } else {
                    // 分配随机大小的数组
                    objects.add(new byte[random.nextInt(100 * 1024)]); // 0 - 100k
                }
            } else if (!objects.isEmpty()) {
                // 释放一些对象
                objects.remove(random.nextInt(objects.size()));
            }

            // 短暂休眠以防止CPU过高
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }

        System.out.println("a");
    }
}

二丶日志分析

默认参数启动

启动参数

java -Xlog:gc*:file=gc.log G1GCDemo2.java
由日志可得(
Heap Region Size: 2M 区域大小
Heap Min Capacity: 8M 最小的堆大小
Heap Initial Capacity: 244M 初始化的堆大小
Heap Max Capacity: 3890M 最大的堆大小

由官方文档可得
image.png

日志分析

初始化

[0.012s][info][gc,init] Version: 17.0.11+1-LTS (release)
[0.012s][info][gc,init] CPUs: 16 total, 16 available
[0.012s][info][gc,init] Memory: 15556M
[0.012s][info][gc,init] Large Page Support: Disabled
[0.012s][info][gc,init] NUMA Support: Disabled
[0.012s][info][gc,init] Compressed Oops: Enabled (Zero based)
[0.012s][info][gc,init] Heap Region Size: 2M
[0.012s][info][gc,init] Heap Min Capacity: 8M
[0.012s][info][gc,init] Heap Initial Capacity: 244M
[0.012s][info][gc,init] Heap Max Capacity: 3890M
[0.012s][info][gc,init] Pre-touch: Disabled
[0.012s][info][gc,init] Parallel Workers: 13
[0.012s][info][gc,init] Concurrent Workers: 3
[0.012s][info][gc,init] Concurrent Refinement Workers: 13
[0.012s][info][gc,init] Periodic GC: Disabled

Heap Region Size: 2M 每个区域大小为2M
Heap Min Capacity: 8M 总区域最小为8M
Heap Initial Capacity: 244M 总区域初始化为244M
Heap Max Capacity: 3890M 总区域最大为3890M

GC0

[0.624s][info][gc,start    ] GC(0) Pause Young (Normal) (G1 Evacuation Pause)
[0.625s][info][gc,task     ] GC(0) Using 5 workers of 13 for evacuation
[0.634s][info][gc,phases   ] GC(0)   Pre Evacuate Collection Set: 0.1ms
[0.634s][info][gc,phases   ] GC(0)   Merge Heap Roots: 0.2ms
[0.634s][info][gc,phases   ] GC(0)   Evacuate Collection Set: 8.7ms
[0.634s][info][gc,phases   ] GC(0)   Post Evacuate Collection Set: 0.7ms
[0.634s][info][gc,phases   ] GC(0)   Other: 0.7ms
[0.634s][info][gc,heap     ] GC(0) Eden regions: 11->0(12)
[0.634s][info][gc,heap     ] GC(0) Survivor regions: 0->2(2)
[0.634s][info][gc,heap     ] GC(0) Old regions: 0->1
[0.634s][info][gc,heap     ] GC(0) Archive regions: 0->0
[0.634s][info][gc,heap     ] GC(0) Humongous regions: 0->0
[0.634s][info][gc,metaspace] GC(0) Metaspace: 9525K(9728K)->9525K(9728K) NonClass: 8390K(8512K)->8390K(8512K) Class: 1134K(1216K)->1134K(1216K)
[0.635s][info][gc          ] GC(0) Pause Young (Normal) (G1 Evacuation Pause) 22M->5M(244M) 10.522ms
[0.635s][info][gc,cpu      ] GC(0) User=0.03s Sys=0.03s Real=0.01s

Pause Young (Normal) (G1 Evacuation Pause) 这是一个年轻代暂停
Eden regions: 11->0(12) eden直接归0
Survivor regions: 0->2(2) survivor多出2个对象
Old regions: 0->1 old一个对象
Archive regions: 0->0 不变
Humongous regions: 0->0 不变
Pause Young (Normal) (G1 Evacuation Pause) 22M->5M(244M) 10.522ms 堆内存从22m减少到5m 耗时10.522ms
GC(0) User=0.03s Sys=0.03s Real=0.01s CPU资源消耗少和应用程序暂停时间都较少

GC1

[0.704s][info][gc,start    ] GC(1) Pause Young (Concurrent Start) (G1 Humongous Allocation)
[0.704s][info][gc,task     ] GC(1) Using 5 workers of 13 for evacuation
[0.708s][info][gc,phases   ] GC(1)   Pre Evacuate Collection Set: 0.1ms
[0.708s][info][gc,phases   ] GC(1)   Merge Heap Roots: 0.0ms
[0.708s][info][gc,phases   ] GC(1)   Evacuate Collection Set: 3.5ms
[0.708s][info][gc,phases   ] GC(1)   Post Evacuate Collection Set: 0.4ms
[0.708s][info][gc,phases   ] GC(1)   Other: 0.3ms
[0.708s][info][gc,heap     ] GC(1) Eden regions: 1->0(27)
[0.708s][info][gc,heap     ] GC(1) Survivor regions: 2->1(2)
[0.708s][info][gc,heap     ] GC(1) Old regions: 1->3
[0.708s][info][gc,heap     ] GC(1) Archive regions: 0->0
[0.708s][info][gc,heap     ] GC(1) Humongous regions: 54->54
[0.708s][info][gc,metaspace] GC(1) Metaspace: 9661K(9920K)->9661K(9920K) NonClass: 8503K(8640K)->8503K(8640K) Class: 1158K(1280K)->1158K(1280K)
[0.708s][info][gc          ] GC(1) Pause Young (Concurrent Start) (G1 Humongous Allocation) 113M->113M(244M) 4.564ms
[0.708s][info][gc,cpu      ] GC(1) User=0.05s Sys=0.02s Real=0.01s

因为大对象过多 所以说垃圾回收阶段的Concurrent阶段开始
Pause Young (Concurrent Start) (G1 Humongous Allocation) 这种类型的收集除了执行正常的年轻收集外,还会启动标记过程。并发标记确定旧生成区域中所有当前可访问的(活动)对象,以保留用于下一个空间回收阶段。虽然收集标记尚未完全完成,但可能会发生正常的年轻收集。标记以两个特殊的停顿结束:备注(Remark)和清理(Cleanup)。(原文如下:Concurrent Start : This type of collection starts the marking process in addition to performing a Normal young collection. Concurrent marking determines all currently reachable (live) objects in the old generation regions to be kept for the following space-reclamation phase. While collection marking hasn’t completely finished, Normal young collections may occur. Marking finishes with two special stop-the-world pauses: Remark and Cleanup. )
image.png

GC2

[0.709s][info][gc          ] GC(2) Concurrent Mark Cycle
[0.709s][info][gc,marking  ] GC(2) Concurrent Clear Claimed Marks
[0.709s][info][gc,marking  ] GC(2) Concurrent Clear Claimed Marks 0.024ms
[0.709s][info][gc,marking  ] GC(2) Concurrent Scan Root Regions
[0.711s][info][gc,marking  ] GC(2) Concurrent Scan Root Regions 1.922ms
[0.711s][info][gc,marking  ] GC(2) Concurrent Mark
[0.711s][info][gc,marking  ] GC(2) Concurrent Mark From Roots
[0.711s][info][gc,task     ] GC(2) Using 3 workers of 3 for marking
[0.712s][info][gc,marking  ] GC(2) Concurrent Mark From Roots 1.580ms
[0.712s][info][gc,marking  ] GC(2) Concurrent Preclean
[0.712s][info][gc,marking  ] GC(2) Concurrent Preclean 0.158ms
[0.712s][info][gc,start    ] GC(2) Pause Remark
[0.713s][info][gc          ] GC(2) Pause Remark 125M->125M(244M) 0.876ms
[0.713s][info][gc,cpu      ] GC(2) User=0.00s Sys=0.00s Real=0.00s
[0.713s][info][gc,marking  ] GC(2) Concurrent Mark 2.880ms
[0.713s][info][gc,marking  ] GC(2) Concurrent Rebuild Remembered Sets
[0.715s][info][gc,marking  ] GC(2) Concurrent Rebuild Remembered Sets 1.249ms
[0.716s][info][gc,start    ] GC(2) Pause Cleanup
[0.716s][info][gc          ] GC(2) Pause Cleanup 133M->133M(244M) 0.076ms
[0.716s][info][gc,cpu      ] GC(2) User=0.00s Sys=0.00s Real=0.00s
[0.716s][info][gc,marking  ] GC(2) Concurrent Cleanup for Next Mark
[0.717s][info][gc,marking  ] GC(2) Concurrent Cleanup for Next Mark 1.359ms
[0.717s][info][gc          ] GC(2) Concurrent Mark Cycle 8.806ms

Concurrent Mark Cycle 表示GC操作进入了并发标记周期

第一阶段
Concurrent Clear Claimed Marks 0.024ms: 表示并发清除之前标记的对象 耗时相当少
Concurrent Scan Root Regions 1.922ms: 表示并发扫描根区域的操作 耗时1.922毫秒。
Concurrent Mark: 表示进入并发标记阶段。
Concurrent Mark From Roots: 表示从根开始并发标记
Using 3 workers of 3 for marking: 表示有3个工作线程参与标记操作。
Concurrent Mark From Roots 1.580ms: 表示从根开始并发标记的操作耗时1.580毫秒。

第二阶段
Concurrent Preclean 0.158ms: 表示并发预清理的操作耗时0.158毫秒

第三阶段
Pause Remark: 表示暂停并进行重新标记(Remark)
Pause Remark 125M->125M(244M) 0.876ms: 表示重新标记阶段将堆内存从125MB处理为125MB(总容量244MB),耗时0.876毫秒
Concurrent Rebuild Remembered Sets 1.249ms: 表示并发重建记忆集的操作耗时1.249毫秒

第四阶段
Pause Cleanup 133M->133M(244M) 0.076ms: 表示清理阶段将堆内存从133MB处理为133MB(总容量244MB),耗时0.076毫秒。

第五阶段
Concurrent Cleanup for Next Mark 1.359ms: 表示并发清理的操作耗时1.359毫秒

第六阶段
Concurrent Cleanup for Next Mark: 表示并发清理以准备下一次标记

Concurrent Mark Cycle 8.806ms: 表示整个并发标记周期耗时8.806毫秒

至此GC日志里面每种类型的日志都已讲述完毕

吞吐量与最大暂停时间

image.png
借助GCeasy 地址:https://gceasy.io/index.jsp#features
可见我们的吞吐量为99.824% 最大暂停时间为10ms
所以说我们的程序目前性能是极其优秀的

所以说我们接下来修改JVM参数以展示不同参数对吞吐量和最大暂停时间的影响

修改参数

影响垃圾回收器性能的因素主要有两类,一类是总堆,一类是年轻一代

修改后的测试程序

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class G1GCDemo2 {
    private static final List<byte[]> longLivedObjects = new ArrayList<>();
    private static final int NUM_LARGE_OBJECTS = 50;
    private static final int LARGE_OBJECT_SIZE = 2048 * 1024; // 2 MB

    public static void main(String[] args) throws Exception {

        Random random = new Random();

        List<byte[]> objects = new ArrayList<>();

        long start = System.currentTimeMillis();

        long end = start + 60 * 1000; // 运行1分钟
        while (System.currentTimeMillis() < end) {
            if (random.nextBoolean()) {
                int r = random.nextInt(3);
                // 分配新的对象
                if(r == 1){
                    if(random.nextBoolean()){
                        // 释放一些对象
                        if(longLivedObjects.size() != 0)
                            longLivedObjects.remove(random.nextInt(longLivedObjects.size()));

                    } else {
                        // 分配大对象
                        longLivedObjects.add(new byte[LARGE_OBJECT_SIZE]);
                    }
                } else {
                    // 分配随机大小的数组
                    objects.add(new byte[random.nextInt(100 * 1024)]); // 0 - 100k
                }
            } else if (!objects.isEmpty()) {
                // 释放一些对象
                if(objects.size() != 0)
                    objects.remove(random.nextInt(objects.size()));
            }

            // 短暂休眠以防止CPU过高
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }

        System.out.println("a");
    }
}

总堆

堆的大小

许多参数会影响生成规模。下图说明了堆中已提交空间和虚拟空间之间的区别。初始化虚拟机时,将保留堆的整个空间。可以使用该 -Xmx 选项指定保留空间的大小。如果 -Xms 参数的值小于 -Xmx 参数的值,则不会立即将所有保留的空间提交到虚拟机。在此图中,未提交的空间被标记为“虚拟”。堆的不同部分,即老一代和年轻一代,可以根据需要增长到虚拟空间的极限。
image.png

java -Xms128m -Xmx128m -Xlog:gc*:file=gc1.log G1GCDemo2.java

image.png
吞吐量为99.154%
最大暂停时间为10.0ms

java -Xms256m -Xmx256m -Xlog:gc*:file=gc2.log G1GCDemo2.java

image.png
吞吐量为99.94% 这几乎已经无法提升了
最大暂停时间仍然为10ms 且平均暂停时间提升了

java -Xms512m -Xmx512m -Xlog:gc*:file=gc3.log G1GCDemo2.java

image.png
吞吐量为99.96% 提升十分少
最大暂停时间仍然为10ms 且平均暂停时间提升了

由此可见 堆大小的提升 可以提升吞吐量但是相应的也增加了平均暂停时间

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages