JVM参数设置及内存溢出
JVM虚拟机参数设置及内存溢出
之前写了一篇关于JVM专题的初步学习,这次来学习虚拟机的参数含义对性能的影响及内存溢出问题。上一篇补充栈上分配
虚拟机提供的一种优化技术,基本思想是,对于线程私有的对象,将它打散分配在栈上,而不分配在堆上。好处是对象跟着方法调用自行销毁,不需要进行垃圾回收,可以提高性能。
栈上分配需要的技术基础,逃逸分析。逃逸分析的目的是判断对象的作用域是否会逃逸出方法体。
任何可以在多个线程之间共享的对象,一定都属于逃逸对象。
下面是测试代码Author:非鸽传书Date:202172820:16Description:VM配置serverXmx10mXms10mXX:DoEscapeAnalysisXX:PrintGCXX:EliminateAllocationsXX:UseTLABserverJVM运行的模式之一,server模式才能进行逃逸分析,JVM运行的模式还有mixclientXmx10m和Xms10m:堆的大小XX:DoEscapeAnalysis:启用逃逸分析(默认打开)XX:PrintGC:打印GC日志XX:EliminateAllocations:标量替换(默认打开):是否允许XX:UseTLAB关闭本地线程分配缓冲TLAB:ThreadLocalAllocBuffer,线程本地分配缓存,事先在堆中开辟线程内存。(虚拟机在分配对象的时候也涉及到加锁,开启这个可以增加分配的效率。注意这里是在堆中所以其他线程仍然是可以访问这部分内存的)publicclassStackAllocatTest{publicstaticclassUser{publicintid0;publicStringname;}publicstaticvoidallocUser(){UserunewUser();u。id1;u。name非鸽传书;}publicstaticvoidmain(String〔〕args){longbeginSystem。currentTimeMillis();for(inti0;i1000000000;i){allocUser();}longendSystem。currentTimeMillis();System。out。println(endbegin);}}分别开启和关闭逃逸分析后对比程序运行时间及GC次数
栈上分配发生影响的参数就是三个,server、XX:DoEscapeAnalysis和XX:EliminateAllocations,任何一个发生变化都不会发生栈上分配。另外jdk1。8默认是开启栈上分配的。对象分配
执行new指令:执行类加载过程为新生对象分配内存。为对象分配空间的任务等同于把一块确定大小的内存从Java堆中划分出来。Java堆中内存是绝对规整的,所有用过的内存都放在一边,空闲的内存放在另一边,中间放着一个指针作为分界点的指示器,那所分配内存就仅仅是把那个指针向空闲空间那边挪动一段与对象大小相等的距离,这种分配方式称为指针碰撞。Java堆中的内存并不是规整的,已使用的内存和空闲的内存相互交错,那就没有办法简单地进行指针碰撞了,虚拟机就必须维护一个列表,记录上哪些内存块是可用的,在分配的时候从列表中找到一块足够大的空间划分给对象实例,并更新列表上的记录,这种分配方式称为空闲列表处理多线程问题方式采用CAS配上失败重试的方式保证更新操作的原子性另一种是把内存分配的动作按照线程划分在不同的空间之中进行,即每个线程在Java堆中预先分配一小块私有内存,也就是本地线程分配缓冲(ThreadLocalAllocationBuffer,TLAB)对象内存布局:
对象头(Header)对象自身的运行时数据如hash码锁状态偏向锁id等等类型指针,指向对象类可以通过这个找到是属于哪个类的实例
实例数据(InstanceData):程序代码中所定义的各种类型的字段内容
对齐填充:虚拟机占位。在Hotspot中要求对象大小必须是8个字节的整数倍。参数含义及参数设置栈:
Xss调整大小,例如Xss256k堆:Xms:堆的最小值
Xmx:堆的最大值;
Xmn:新生代的大小;
XX:NewSize;新生代最小值;
XX:MaxNewSize:新生代最大值;方法区永久代jdk1。7及以前:XX:PermSize;XX:MaxPermSize;
jdk1。8以后:XX:MetaspaceSize;XX:MaxMetaspaceSize
jdk1。8以后大小就只受本机总内存的限制
如:XX:MaxMetaspaceSize3M直接内存
XX:MaxDirectMemorySize
其他更多的命令可百度或者谷歌查询。
Tip:XX表示运行参数OOM堆溢出
虚拟机参数:Xms5mXmx5mXX:PrintGC
代码片段1:publicclassOOMHeap{publicstaticvoidmain(String〔〕args){ListObjectlistnewLinkedList();inti0;try{while(true){i;if(i100000){System。out。println(i);}list。add(String。valueOf(i));}}catch(Throwablee){System。out。println(i:iError:e);}}}输出如下〔GC(AllocationFailure)1020K656K(5632K),0。0016767secs〕〔GC(AllocationFailure)1680K879K(5632K),0。0011192secs〕〔GC(AllocationFailure)1903K1403K(5632K),0。0084106secs〕10000〔GC(AllocationFailure)2427K2443K(5632K),0。0041601secs〕2000030000〔GC(AllocationFailure)3467K3491K(5632K),0。0048149secs〕〔FullGC(Ergonomics)3491K3256K(5632K),0。0697227secs〕40000〔FullGC(Ergonomics)4280K4257K(5632K),0。0457067secs〕50000〔FullGC(Ergonomics)4770K4769K(5632K),0。0194403secs〕〔FullGC(Ergonomics)4770K4770K(5632K),0。0190617secs〕。。。i:55128Error:java。lang。OutOfMemoryError:GCoverheadlimitexceeded
代码片段2:publicclassOOMHeap{publicstaticvoidmain(String〔〕args){String〔〕strsnewString〔1000000000〕;}}输出:〔GC(AllocationFailure)1020K664K(5632K),0。0013220secs〕〔GC(AllocationFailure)1688K879K(5632K),0。0019375secs〕〔GC(AllocationFailure)1495K975K(5632K),0。0021262secs〕〔GC(AllocationFailure)975K999K(5632K),0。0009794secs〕〔FullGC(AllocationFailure)999K914K(5632K),0。0077754secs〕〔GC(AllocationFailure)914K914K(5632K),0。0003017secs〕〔FullGC(AllocationFailure)914K896K(5632K),0。0103908secs〕Exceptioninthreadmainjava。lang。OutOfMemoryError:Javaheapspace。。。java。lang。OutOfMemoryError:GCoverheadlimitexceeded一般是(某个循环里可能性最大)在不停地分配对象,但是分配得太多,把堆撑爆了。java。lang。OutOfMemoryError:Javaheapspace一般是分配了巨型对象栈溢出
虚拟机参数:Xss256kpublicclassOOMStackTest{privateintdeepen1;privatevoidrecurrence(){deepen;recurrence();}publicstaticvoidmain(String〔〕args){OOMStackTesttestnewOOMStackTest();try{test。recurrence();}catch(Throwablee){System。out。println(stackdeeptest。deepen);e。printStackTrace();}}}输出stackdeep20733java。lang。StackOverflowErroratcom。jmmq。load。jim。jvm。OOMStackTest。recurrence(OOMStackTest。java:17)atcom。jmmq。load。jim。jvm。OOMStackTest。recurrence(OOMStackTest。java:17)atcom。jmmq。load。jim。jvm。OOMStackTest。recurrence(OOMStackTest。java:17)。。。递归参数如果增加参数列表则栈深度会变小,因为参数也会打包到栈帧中
java。lang。StackOverflowError一般的方法调用是很难出现的,如果出现了要考虑是否有无限递归。直接内存溢出
虚拟机参数Xmx10MXX:MaxDirectMemorySize10MpublicclassOOMDirectMemory{publicstaticvoidmain(String〔〕args){ByteBufferbufferByteBuffer。allocate(1024102411);}}输出Exceptioninthreadmainjava。lang。OutOfMemoryError:Javaheapspaceatjava。nio。HeapByteBuffer。init(HeapByteBuffer。java:57)atjava。nio。ByteBuffer。allocate(ByteBuffer。java:335)atcom。jmmq。load。jim。jvm。OOMDirectMemory。main(OOMDirectMemory。java:12)