虚拟机学习 :ArrayList 插入1000万条数据之后,GC + OSR

转载自:公众号 :石杉架构笔记

List<Integer> list0 = new ArrayList<Integer>();
long start0 = System.currentTimeMillis();
for (int i = 0; i < 10000000; i++) {
    list0.add(i);
}
System.out.println(System.currentTimeMillis() - start0);

long start1 = System.currentTimeMillis();
List<Integer> list1 = new ArrayList<Integer>();
for (int i = 10000000; i < 20000000; i++) {
    list1.add(i);
}

System.out.println(System.currentTimeMillis() - start1);

"在一个ArrayList中连续插入1千万条数据,结果耗时不一样,分别是 6883 和 669 "

VM增加参数: -XX:+PrintGCDetails -XX:+PrintGCDateStamps"   ---- 发现两次执行时发生了不同程序的 GC(Minor GC) 和 Full GC

2019-10-27T10:20:11.211+0800: [GC (Allocation Failure) [PSYoungGen: 33280K->5100K(38400K)] 33280K->21048K(125952K), 0.0626695 secs] [Times: user=0.13 sys=0.01, real=0.06 secs] 
2019-10-27T10:20:11.287+0800: [GC (Allocation Failure) [PSYoungGen: 38380K->5104K(71680K)] 54328K->41815K(159232K), 0.0622557 secs] [Times: user=0.16 sys=0.00, real=0.06 secs] 
2019-10-27T10:20:11.375+0800: [GC (Allocation Failure) [PSYoungGen: 55045K->5104K(71680K)] 91757K->91696K(159232K), 0.1872819 secs] [Times: user=0.34 sys=0.02, real=0.19 secs] 
2019-10-27T10:20:11.563+0800: [Full GC (Ergonomics) [PSYoungGen: 5104K->0K(71680K)] [ParOldGen: 86592K->80796K(190464K)] 91696K->80796K(262144K), [Metaspace: 3283K->3283K(1056768K)], 1.9832553 secs] [Times: user=3.04 sys=0.00, real=1.98 secs] 
2019-10-27T10:20:13.623+0800: [GC (Allocation Failure) [PSYoungGen: 66560K->5120K(103936K)] 183411K->158795K(294400K), 0.2398399 secs] [Times: user=0.72 sys=0.05, real=0.24 secs] 
2019-10-27T10:20:13.863+0800: [Full GC (Ergonomics) [PSYoungGen: 5120K->0K(103936K)] [ParOldGen: 153675K->142683K(301568K)] 158795K->142683K(405504K), [Metaspace: 3283K->3283K(1056768K)], 1.5632428 secs] [Times: user=3.63 sys=0.00, real=1.56 secs] 
2019-10-27T10:20:15.469+0800: [GC (Allocation Failure) [PSYoungGen: 98816K->5120K(138240K)] 241499K->241605K(439808K), 0.2151242 secs] [Times: user=0.73 sys=0.02, real=0.21 secs] 
2019-10-27T10:20:15.684+0800: [Full GC (Ergonomics) [PSYoungGen: 5120K->0K(138240K)] [ParOldGen: 236485K->205394K(455680K)] 241605K->205394K(593920K), [Metaspace: 3283K->3283K(1056768K)], 2.3706106 secs] [Times: user=5.77 sys=0.00, real=2.37 secs] 

First array Insert time cost: 6883

2019-10-27T10:20:18.124+0800: [GC (Allocation Failure) [PSYoungGen: 118118K->85816K(221184K)] 323513K->291211K(676864K), 0.1873546 secs] [Times: user=0.45 sys=0.06, real=0.19 secs] 
2019-10-27T10:20:18.376+0800: [GC (Allocation Failure) [PSYoungGen: 210232K->110071K(234496K)] 415627K->375609K(690176K), 0.3202792 secs] [Times: user=1.01 sys=0.06, real=0.32 secs] 

Second Insert time cost: 669

Heap
 PSYoungGen      total 234496K, used 196232K [0x00000000d5580000, 0x00000000f3e00000, 0x0000000100000000)
    eden space 124416K, 69% used [0x00000000d5580000,0x00000000da9a4570,0x00000000dcf00000)
    from space 110080K, 99% used [0x00000000dcf00000,0x00000000e3a7dc60,0x00000000e3a80000)
    to   space 160256K, 0% used [0x00000000ea180000,0x00000000ea180000,0x00000000f3e00000)
 
 ParOldGen       total 455680K, used 265538K [0x0000000080000000, 0x000000009bd00000, 0x00000000d5580000)
    object space 455680K, 58% used [0x0000000080000000,0x0000000090350b40,0x000000009bd00000)
 Metaspace       used 3295K, capacity 4556K, committed 4864K, reserved 1056768K
    class space    used 350K, capacity 392K, committed 512K, reserved 1048576K

JVM内存分布(截取自 纯洁的微笑 博客)


在重新调整堆大小后,不再发生GC的情况下,仍然前一个都比后一个耗时多点,这是怎么回事?

放在"在不同线程中执行,两者耗时几乎一致,这是为什么?"

原因:OSR


OSR(On-Stack Replacement ),是一种在运行时替换正在运行的函数/方法的栈帧的技术。

在现代的主流JVM中,都具备了多层编译的能力,一开始以解释的方式进行执行,这种性能相对来说(和c++比)会慢一点

但是一旦发现某一个函数执行很频繁的时候,就会采用JIT编译,提高函数执行性能(大部分比c++还快)。

但是,如果以函数为单位进行JIT编译,那么就无法应对main函数中包含循环体的情况,这个时候,OSR就派上了用场。

与其编译整个方法,我们可以在发现某个方法里有循环很热的时候,选择只编译方法里的某个循环,当循环体执行到 i = 5000 的时候,循环计数器达到了触发OSR编译的阈值,等编译完成之后,就可以执行编译后生成的代码。

所以在上面例子中,当我们第二次执行循环体的时候,已经在执行OSR编译后的代码,那么在性能上会比前一次会快那么一点点。

猜你喜欢

转载自www.cnblogs.com/clarino/p/11746802.html