java并发编程学习整理-JVM内存分配+测试篇——前方高能不喜请绕路 weir 2018-04-21 11:30:24.0 java,并发 3096 JVM我不说太多了,java最底层的部份,学习研究有什么用处?当然个人兴趣,想研究底层实现原理,想自己实现JVM等等可以给自己找出各种理由来, 其重要性我觉得也不用说太多,理论性的也不用废话,还是来实际的测试研究更直观,至少对他有一些直观的感受也是挺不错的。 好好看看这张图,不妥之处请指教。 -Xms2m -Xmx2m -Xms10m -Xmx10m 第一次设置2m 第二次设置10m 大家看看输出,或者多试几次看看,能得出一些自己的结论 堆的参数 1:Xms:初始堆大小,默认物理内存的1/64(<1g) 2:Xmx:最大堆大小,默认物理内存的1/4(<1G) 建议xms=xmx,好处是避免每次gc后,调整堆的大小,减少系统内存分配开销 这段代码大家优惠看到什么名堂,bs只能分配8m的内存,(堆内存)就溢出了。我这里用的是-Xms10m -Xmx10m 这几为什么list.add(new M1()); 大家思考思考??为什么是new M1()??? 堆内存溢出分析: -Xms10m -Xmx10m -XX:+HeapDumpOnOutOfMemoryError http://www.eclipse.org/mat/downloads.php 装插件 对简单的分析可以真正项目去用这个分析那就有点扯淡了! 2:打印GC详细信息 -XX:+PrintGCDetails 打印GC分析下: [GC (Allocation Failure) [PSYoungGen: 512K->488K(1024K)] 512K->520K(1536K), 0.0008395 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] [GC (Allocation Failure) [PSYoungGen: 839K->504K(1536K)] 5991K->5736K(7168K), 0.0005705 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] [GC (Allocation Failure) [PSYoungGen: 504K->488K(1536K)] 5736K->5792K(7168K), 0.0005661 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] [Full GC (Allocation Failure) [PSYoungGen: 488K->430K(1536K)] [ParOldGen: 5304K->5248K(5632K)] 5792K->5678K(7168K), [Metaspace: 2753K->2753K(1056768K)], 0.0039087 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] [GC (Allocation Failure) [PSYoungGen: 430K->480K(2048K)] 5678K->5792K(7680K), 0.0005207 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] [Full GC (Allocation Failure) [PSYoungGen: 480K->380K(2048K)] [ParOldGen: 5312K->5285K(5632K)] 5792K->5666K(7680K), [Metaspace: 2753K->2753K(1056768K)], 0.0042998 secs] [Times: user=0.09 sys=0.00, real=0.00 secs] [GC (Allocation Failure) --[PSYoungGen: 1404K->1404K(2048K)] 6690K->6698K(7680K), 0.0005353 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] [Full GC (Ergonomics) [PSYoungGen: 1404K->1401K(2048K)] [ParOldGen: 5293K->5289K(5632K)] 6698K->6690K(7680K), [Metaspace: 2753K->2753K(1056768K)], 0.0034402 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] [GC (Allocation Failure) --[PSYoungGen: 1401K->1401K(2048K)] 6690K->6690K(7680K), 0.0004705 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] [Full GC (Allocation Failure) [PSYoungGen: 1401K->1401K(2048K)] [ParOldGen: 5289K->5289K(5632K)] 6690K->6690K(7680K), [Metaspace: 2753K->2753K(1056768K)], 0.0034706 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] java.lang.OutOfMemoryError: Java heap space Dumping heap to java_pid10712.hprof ... Heap dump file created [7574184 bytes in 0.010 secs] mm====7 java.lang.OutOfMemoryError: Java heap space at weir.jvm.memory.M1.(M1.java:8) at weir.jvm.memory.M1.main(M1.java:17) Heap PSYoungGen total 2048K, used 1463K [0x00000000ffd80000, 0x0000000100000000, 0x0000000100000000) eden space 1536K, 95% used [0x00000000ffd80000,0x00000000ffeedc10,0x00000000fff00000) from space 512K, 0% used [0x00000000fff80000,0x00000000fff80000,0x0000000100000000) to space 512K, 0% used [0x00000000fff00000,0x00000000fff00000,0x00000000fff80000) ParOldGen total 5632K, used 5289K [0x00000000ff800000, 0x00000000ffd80000, 0x00000000ffd80000) object space 5632K, 93% used [0x00000000ff800000,0x00000000ffd2a410,0x00000000ffd80000) Metaspace used 2785K, capacity 4486K, committed 4864K, reserved 1056768K class space used 298K, capacity 386K, committed 512K, reserved 1048576K GC日志格式简要说明 1:GC发生的时间,也就是JVM从启动以来经过的秒数 2:停顿类型,比如:[GC或[Full GC,如果是调用的System.gc(),那么是[Full GC(System) 3:GC发生的区域名称,比如:[DefNew、[Tenured、[Perm、[ParNew等,如果采用Parallel Scavenge收集器,那么是[PSYoungGen,老年代与此类似 4:容量:GC前容量-〉GC后容量(该区域总容量) 5:GC持续时间,单位秒。有的收集器会有更详细的描述,比如:user表示消耗的时间,sys表 示系统内核消耗的时间、real表示操作从开始到结束的时间 对照仔细分析下 3:Xmn:新生代大小,默认整个堆的3/8 [GC (Allocation Failure) [PSYoungGen: 512K->488K(1024K)] 512K->520K(1536K), 0.0010896 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] [GC (Allocation Failure) [PSYoungGen: 839K->488K(1536K)] 1895K->1660K(3584K), 0.0011880 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] [GC (Allocation Failure) [PSYoungGen: 488K->504K(1536K)] 1660K->1708K(3584K), 0.0006447 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] [Full GC (Allocation Failure) [PSYoungGen: 504K->0K(1536K)] [ParOldGen: 1204K->1582K(2048K)] 1708K->1582K(3584K), [Metaspace: 2750K->2750K(1056768K)], 0.0057209 secs] [Times: user=0.01 sys=0.00, real=0.02 secs] [GC (Allocation Failure) [PSYoungGen: 0K->0K(2560K)] 1582K->1582K(4608K), 0.0003520 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] [Full GC (Allocation Failure) [PSYoungGen: 0K->0K(2560K)] [ParOldGen: 1582K->1570K(2048K)] 1582K->1570K(4608K), [Metaspace: 2750K->2750K(1056768K)], 0.0054823 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] [GC (Allocation Failure) --[PSYoungGen: 1024K->1024K(2560K)] 2594K->2594K(4608K), 0.0006981 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] [Full GC (Ergonomics) [PSYoungGen: 1024K->1024K(2560K)] [ParOldGen: 1570K->1570K(2048K)] 2594K->2594K(4608K), [Metaspace: 2750K->2750K(1056768K)], 0.0024676 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] [GC (Allocation Failure) --[PSYoungGen: 1024K->1024K(2560K)] 2594K->2594K(4608K), 0.0004642 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] [Full GC (Allocation Failure) [PSYoungGen: 1024K->1024K(2560K)] [ParOldGen: 1570K->1570K(2048K)] 2594K->2594K(4608K), [Metaspace: 2750K->2750K(1056768K)], 0.0018686 secs] [Times: user=0.02 sys=0.00, real=0.02 secs] java.lang.OutOfMemoryError: Java heap space Dumping heap to java_pid8808.hprof ... Heap dump file created [3379733 bytes in 0.007 secs] mm====3 java.lang.OutOfMemoryError: Java heap space at weir.jvm.memory.M1.(M1.java:8) at weir.jvm.memory.M1.main(M1.java:17) Heap PSYoungGen total 2560K, used 1106K [0x00000000ffa00000, 0x00000000ffd00000, 0x0000000100000000) eden space 2048K, 54% used [0x00000000ffa00000,0x00000000ffb14840,0x00000000ffc00000) from space 512K, 0% used [0x00000000ffc80000,0x00000000ffc80000,0x00000000ffd00000) to space 512K, 0% used [0x00000000ffc00000,0x00000000ffc00000,0x00000000ffc80000) ParOldGen total 2048K, used 1570K [0x00000000ff800000, 0x00000000ffa00000, 0x00000000ffa00000) object space 2048K, 76% used [0x00000000ff800000,0x00000000ff988920,0x00000000ffa00000) Metaspace used 2783K, capacity 4486K, committed 4864K, reserved 1056768K class space used 298K, capacity 386K, committed 512K, reserved 1048576K 大家看到有没有不正常的地方,你分配给新生代6m,老年代只有1m,这肯定是不符合jvm里面的逻辑点的(一般新生代内存大小要低于老年代的这是jvm规范的一般共识,你要是违背了jvm是不会听从你的安排的) 设置为1m试试 [GC (Allocation Failure) [PSYoungGen: 512K->504K(1024K)] 512K->528K(1536K), 0.0008146 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] [GC (Allocation Failure) [PSYoungGen: 855K->488K(1024K)] 7023K->6788K(7680K), 0.0008893 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] [GC (Allocation Failure) [PSYoungGen: 488K->488K(1024K)] 6788K->6820K(7680K), 0.0006159 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] [Full GC (Allocation Failure) [PSYoungGen: 488K->417K(1024K)] [ParOldGen: 6332K->6285K(6656K)] 6820K->6702K(7680K), [Metaspace: 2750K->2750K(1056768K)], 0.0041237 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] [GC (Allocation Failure) [PSYoungGen: 417K->504K(1024K)] 6702K->6797K(7680K), 0.0009821 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] [Full GC (Allocation Failure) [PSYoungGen: 504K->412K(1024K)] [ParOldGen: 6293K->6277K(6656K)] 6797K->6690K(7680K), [Metaspace: 2750K->2750K(1056768K)], 0.0039854 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] java.lang.OutOfMemoryError: Java heap space Dumping heap to java_pid16040.hprof ... Heap dump file created [7574241 bytes in 0.009 secs] mm====7 java.lang.OutOfMemoryError: Java heap space at weir.jvm.memory.M1.(M1.java:8) at weir.jvm.memory.M1.main(M1.java:17) Heap PSYoungGen total 1024K, used 433K [0x00000000ffe80000, 0x0000000100000000, 0x0000000100000000) eden space 512K, 4% used [0x00000000ffe80000,0x00000000ffe85330,0x00000000fff00000) from space 512K, 80% used [0x00000000fff80000,0x00000000fffe7340,0x0000000100000000) to space 512K, 0% used [0x00000000fff00000,0x00000000fff00000,0x00000000fff80000) ParOldGen total 6656K, used 6277K [0x00000000ff800000, 0x00000000ffe80000, 0x00000000ffe80000) object space 6656K, 94% used [0x00000000ff800000,0x00000000ffe21680,0x00000000ffe80000) Metaspace used 2782K, capacity 4486K, committed 4864K, reserved 1056768K class space used 298K, capacity 386K, committed 512K, reserved 1048576K Java HotSpot(TM) 64-Bit Server VM warning: NewSize (1536k) is greater than the MaxNewSize (1024k). A new max generation size of 1536k will be used. 再看看是不是正常多了 4:-XX:NewRatio:老年代与新生代的比值,不包含持久代 如果xms=xmx,且设置了xmn的情况下,该参数不需要设置 [GC (Allocation Failure) [PSYoungGen: 512K->488K(1024K)] 512K->512K(1536K), 0.0006455 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] [GC (Allocation Failure) [PSYoungGen: 839K->488K(1024K)] 3935K->3688K(5120K), 0.0012780 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] [GC (Allocation Failure) [PSYoungGen: 488K->504K(1024K)] 3688K->3760K(5120K), 0.0006799 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] [Full GC (Allocation Failure) [PSYoungGen: 504K->0K(1024K)] [ParOldGen: 3256K->3630K(4096K)] 3760K->3630K(5120K), [Metaspace: 2752K->2752K(1056768K)], 0.0059804 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] [GC (Allocation Failure) [PSYoungGen: 0K->0K(1536K)] 3630K->3630K(5632K), 0.0004346 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] [Full GC (Allocation Failure) [PSYoungGen: 0K->0K(1536K)] [ParOldGen: 3630K->3618K(4096K)] 3630K->3618K(5632K), [Metaspace: 2752K->2752K(1056768K)], 0.0057154 secs] [Times: user=0.02 sys=0.00, real=0.01 secs] mm====4 java.lang.OutOfMemoryError: Java heap space at weir.jvm.memory.M1.(M1.java:8) at weir.jvm.memory.M1.main(M1.java:17) Heap PSYoungGen total 1536K, used 41K [0x00000000ffe00000, 0x0000000100000000, 0x0000000100000000) eden space 1024K, 4% used [0x00000000ffe00000,0x00000000ffe0a4d8,0x00000000fff00000) from space 512K, 0% used [0x00000000fff80000,0x00000000fff80000,0x0000000100000000) to space 512K, 0% used [0x00000000fff00000,0x00000000fff00000,0x00000000fff80000) ParOldGen total 4096K, used 3618K [0x00000000ffa00000, 0x00000000ffe00000, 0x00000000ffe00000) object space 4096K, 88% used [0x00000000ffa00000,0x00000000ffd88960,0x00000000ffe00000) Metaspace used 2785K, capacity 4486K, committed 4864K, reserved 1056768K class space used 298K, capacity 386K, committed 512K, reserved 1048576K -XX:NewRatio=2 意思是6m的 老年代是2/3 新生代是1/3 看看是不是这么回事 这种比例分配会达到比较好的预期,注意这个比值只能是整数 你可以设置1:1试试,,如果只设置新生代比如按默认的3/8 也会达到比较好的预期,再大就不好了,大家可以自己试试 -Xmn 与 -XX:NewRatio 二选一,,现在只有新生代和老年代这两个了,设置好一个那另外一个就确定了。 5:-XX:SurvivorRatio:Eden区和Survivor区的大小比值,设置为8,则两个Survivor区与一 个Eden区的比值为2:8,一个Survivor占整个新生的1/10 这个大家试试看就知道了 6:新建的对象也有可能直接进入老年代,比如: 大对象,可通过设置-XX:PretenureSizeThreshold=1024(单位为字节,默认为0)来代表超过多大时就不在新生代分配,而是直接在老年代分配 这个怎么测试大家也试试吧,其实就是把private byte[] bs = new byte[1024*1024*2]; 看看内存是放在了新生代还是老年代 7: -XX:+HeapDumpOnOutOfMemoryError:OOM时导出堆到文件 8: -XX:+HeapDumpPath:导出OOM的路径 9: -XX:OnOutOfMemoryError:在OOM时,执行一个脚本,例如: -XX:OnOutOfMemoryError=D:/mytest.bat %p 这个是报错的话去执行一个脚本,这个作用就比较广了,导出日志信息,发邮件等等 推荐配置 1:根据实际应用来调整新生代和幸存代的大小 2:官方推荐新生代占堆的3/8 3:幸存代占新生代的1/10 4:在OOM时,记得Dump出堆,确保可以排查现场问题 Java栈的参数 n -Xss 通常只有几百K 决定了函数调用的深度 Jdk8 最低160k 内存再分配的大一点再看看深度,大家试试就行了,栈溢出一般都是递归或循环调用造成的 元空间的参数 n 元空间的参数 1:-XX:MetaspaceSize 初始空间大小,达到该值就会触发垃圾收集进行类型卸载,同时GC会对该值进行调 整:如果释放了大量的空间,就适当降低该值;如果释放了很少的空间,那么在不超过 MaxMetaspaceSize时,适当提高该值 虚拟机可以动态作调整 2:-XX:MaxMetaspaceSize 最大空间,默认是没有限制的 我本来想测试一下元空间溢出的效果的,但是找了半天都没测试出来,这个谁要是有测试用例可以交流下。 3:-XX:MinMetaspaceFreeRatio 在GC之后,最小的Metaspace剩余空间容量的百分比,减少为分配空间所导致的垃圾收集 4:-XX:MaxMetaspaceFreeRatio 在GC之后,最大的Metaspace剩余空间容量的百分比,减少为释放空间所导致的垃圾收集