本篇文章基于V0.16 JOLSample_27_Colocation
这篇例子用来演示VM如何管理不同线程分配的对象。
在例子中,ConcurrentHashMap
被多个线程填充。我们可以看到经过几次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 51 52 53 54 55 56 57 58
| public class JOLSample_27_Colocation {
public static volatile Object sink;
public static void main(String[] args) throws Exception { out.println(VM.current().details());
for (int c = 0; c < 1000000; c++) { sink = new Object(); } System.gc();
final int COUNT = 1000;
ConcurrentHashMap<Object, Object> chm = new ConcurrentHashMap<>();
addElements(COUNT, chm);
GraphLayout.parseInstance(chm).toImage("chm-1-new.png");
for (int c = 2; c <= 5; c++) { GraphLayout.parseInstance(chm).toImage("chm-" + c + "-gc.png"); System.gc(); }
addElements(COUNT, chm);
for (int c = 6; c <= 10; c++) { GraphLayout.parseInstance(chm).toImage("chm-" + c + "-more-gc.png"); System.gc(); }
}
private static void addElements(final int count, final Map<Object, Object> chm) throws InterruptedException { ExecutorService pool = Executors.newCachedThreadPool();
Runnable task = new Runnable() { @Override public void run() { for (int c = 0; c < count; c++) { Object o = new Object(); chm.put(o, o); } } };
for (int t = 0; t < Runtime.getRuntime().availableProcessors() * 2; t++) { pool.submit(task); }
pool.shutdown(); pool.awaitTermination(1, TimeUnit.DAYS); }
}
|
- 先分配了100万个临时小对象,然后GC, 接着继续往ConcurrentHashMap添加100个小对象,然后输出
- 再输出一次
- GC一次,再输出一次
- GC一次,再输出一次
- GC一次,再输出一次
- 继续往ConcurrentHashMap添加100个小对象,然后输出
- GC一次,再输出一次
- GC一次,再输出一次
- GC一次,再输出一次
- GC一次,再输出一次