JOL 26 Defragmentation


本篇文章基于V0.16 JOLSample_26_Defragmentation

本例是用来演示VM如何对堆进行碎片整理的。

在本例中我们有一个对象数组,这些对象很紧密地分配在了一起,而且在多次GC中都存活了下来。然后我们随机清理一半的元素。现在对象布局就很稀疏了。
然后继续GC。

运行这个例子最好使用参数

1
-Xmx1g -XX:+UseParallelGC -XX:ParallelGCThreads=1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
public class JOLSample_26_Defragmentation {

public static volatile Object sink;

public static void main(String[] args) throws Exception {
out.println(VM.current().details());

// allocate some objects to beef up generations
for (int t = 0; t < 1000000; t++) {
sink = new Object();
}
System.gc();

final int COUNT = 10000;

Object[] array = new Object[COUNT];
for (int c = 0; c < COUNT; c++) {
array[c] = new Object();
}

Object obj = array;

GraphLayout.parseInstance(obj).toImage("array-1-new.png");

for (int c = 2; c <= 5; c++) {
for (int t = 0; t < 1000000; t++) {
sink = new Object();
}
System.gc();
GraphLayout.parseInstance(obj).toImage("array-" + c + "-before.png");
}

for (int c = 0; c < COUNT; c++) {
if (Math.random() < 0.5) {
array[c] = null;
}
}

GraphLayout.parseInstance(obj).toImage("array-6-after.png");

for (int c = 7; c <= 10; c++) {
for (int t = 0; t < 1000000; t++) {
sink = new Object();
}
System.gc();
GraphLayout.parseInstance(obj).toImage("array-" + c + "-after-gc.png");
}
}

}
  1. 先分配了100万个临时小对象,然后GC掉

  1. 接着给数组对象分配1个小对象,现在是数组对象后面跟着1个Object对象。然后输出

  1. 继续分配100万个临时小对象,GC。输出为

  1. 继续分配100万个临时小对象,GC。输出为

  1. 继续分配100万个临时小对象,GC。输出为

  1. 清理掉一半的数组对象,输出为

  1. 继续分配100万个临时小对象,GC。输出为

  1. 继续分配100万个临时小对象,GC。输出为

  1. 继续分配100万个临时小对象,GC。输出为

  1. 继续分配100万个临时小对象,GC。输出为

通过整个过程我们可以看到,第一次多次生成临时对象和第二次多次生成临时对象,它们的内存分配地址就不再发生变化了,这也验证了上篇文章中的说法,每次GC之后又回到了相同的起始地址。