JVM介绍及参数配置
1.堆内存和非堆内存组成
堆内存:分为年轻代和老年代
年轻代:Eden区和两个存活区
Q:为什么对堆要分年轻代,老年代,伊甸园区,存活区?
A:减少FGC的频率,减少程序暂停的时间,提高性能,如果不分区,很快堆内存满了就会触发GC,对整个堆进行垃圾回收,而堆内存较大,会耗费很长时间,程序暂停时间过长,影响性能
2.堆内存存放的是new出来的对象和数组
非堆内存存放的是常量、静态变量、方法区、内存计数器
3.栈是运行时的单位,而堆是存储的单位。
栈解决程序的运行问题,即程序如何执行,或者说如何处理数据;堆解决的是数据存储的问题,而数据怎么放、放在哪儿。
栈:运行
堆:存储
4.JVM heap内存空间划分
分配原则:
- 对象优先在Eden中分配,当伊甸园区满了之后会触发YGC,YGC进行寻根判断,被引用的对象进入存活区,未被引用的对象被当做垃圾回收
当Survivor中放不下时,则由分派担保进入老年代中。 - 大对象直接进入老年代中。 -XX:+PretenuerSizeThreshold 控制”大对象的“的大小,如果对象大小大于设置值直接放入老年代。
- 长期存活的对象将进入老年代(默认age=15的对象叫长期存活对象,也可以用参数进行配置);
- 动态对象年龄判定:虚拟机并不总是要求对象的年龄必须达到MaxTenuringThreshold才能晋升到老年代,如果在Survivor区中相同年龄的对象的所有大小之和超过Survivor空间的一半,年龄大于或等于该年龄的对象就可以直接进入老年代,无需等到MaxTenuringThreshold中要求的年龄(如age=5的对象很多,加起来大于存活区大小的一半了,那些age>=5的对象就会进入老年代);
JVM年轻代垃圾回收:
新对象首先在eden区分配空间,当eden区满时,还存活的对象将被复制到一个survivor区。当这个survivor区满时,存活对象会被复制到另一个survivor区。当第二个survivor区也满了时,存活对象被复制到老年代。 2个survivor区是完全对称的,轮流替换。
触发FGC的三种情况
- 老年代满了之后,触发FGC;
- 被显示调用的时候会触发FGC(runtime.gc() system.gc());
- 悲观策略(基于rmi的框架,框架中会定义隔一段时间在代码中显示调用system.gc())也会调用FGC;
- jmap -dump 也会触发FGC
调优方法:
一般情况:
- 多数的Java应用不需要在服务器上进行GC优化;
- 多数导致GC问题的Java应用,都不是因为我们参数设置错误,而是代码问题;
- 在应用上线之前,先考虑将机器的JVM参数设置到最优(最适合);
- 减少创建对象的数量;
- 减少使用全局变量和大对象;
- GC优化是到最后不得已才采用的手段;
- 在实际使用中,分析GC情况优化代码比优化GC参数要多得多;
GC优化的目的有两个:
- 将转移到老年代的对象数量降低到最小;
- 减少full GC的执行时间;
为了达到上面的目的,一般地,需要做的事情有:
- 减少使用全局变量和大对象;
- 调整新生代的大小到最合适;
- 设置老年代的大小为最合适;
- 选择合适的GC收集器;
1. 不管是YGC还是Full GC,GC过程中都会对导致程序运行中中断,正确的选择不同的GC策略,调整JVM、GC的参数,可以极大的减少由于GC工作,而导致的程序运行中断方面的问题,进而适当的提高Java程序的工作效率;
2. FGC会对整个堆和非堆(包含持久带)进行垃圾回收 ;
3. YGC只会对伊甸园区和存活区进行垃圾回收;
参数名称
|
含义
|
默认值
|
备注 |
-Xms
|
初始堆大小
|
物理内存的1/64(<1GB)
|
默认(MinHeapFreeRatio参数可以调整)空余堆内存小于40%时,JVM就会增大堆直到-Xmx的最大限制.
|
-Xmx
|
最大堆大小
|
物理内存的1/4(<1GB)
|
默认(MaxHeapFreeRatio参数可以调整)空余堆内存大于70%时,JVM会减少堆直到 -Xms的最小限制
|
-Xmn
|
年轻代大小(1.4or lator)
|
注意:此处的大小是(eden+ 2 survivor space).与jmap -heap中显示的New gen是不同的。
整个堆大小=年轻代大小 + 年老代大小 + 持久代大小.
增大年轻代后,将会减小年老代大小.此值对系统性能影响较大,Sun官方推荐配置为整个堆的3/8
|
|
-XX:NewSize
|
设置年轻代大小(for 1.3/1.4)
|
||
-XX:MaxNewSize
|
年轻代最大值(for 1.3/1.4)
|
||
-XX:PermSize
|
设置持久代(perm gen)初始值
|
物理内存的1/64
|
|
-XX:MaxPermSize
|
设置持久代最大值
|
物理内存的1/4
|
|
-Xss
|
每个线程的堆栈大小
|
JDK5.0以后每个线程堆栈大小为1M,以前每个线程堆栈大小为256K.更具应用的线程所需内存大小进行 调整.在相同物理内存下,减小这个值能生成更多的线程.但是操作系统对一个进程内的线程数还是有限制的,不能无限生成,经验值在3000~5000左右
一般小的应用, 如果栈不是很深, 应该是128k够用的 大的应用建议使用256k。这个选项对性能影响比较大,需要严格的测试。(校长)
和threadstacksize选项解释很类似,官方文档似乎没有解释,在论坛中有这样一句话:"”
-Xss is translated in a VM flag named ThreadStackSize”
一般设置这个值就可以了。
|
|
-XX:ThreadStackSize
|
Thread Stack Size
|
(0 means use default stack size) [Sparc: 512; Solaris x86: 320 (was 256 prior in 5.0 and earlier); Sparc 64 bit: 1024; Linux amd64: 1024 (was 0 in 5.0 and earlier); all others 0.]
|
|
-XX:NewRatio
|
年轻代(包括Eden和两个Survivor区)与年老代的比值(除去持久代)
|
-XX:NewRatio=4表示年轻代与年老代所占比值为1:4,年轻代占整个堆栈的1/5
Xms=Xmx并且设置了Xmn的情况下,该参数不需要进行设置。
|
|
-XX:SurvivorRatio
|
Eden区与Survivor区的大小比值
|
设置为8,则两个Survivor区与一个Eden区的比值为2:8,一个Survivor区占整个年轻代的1/10
|