堆实质上分为三大块,年轻代(YoungGen),年老代(Old Memory),及持久代(Perm,在jdk8中被取消,替换为MetaSpace(元空间)存在于本地内存)。垃圾回收GC,分为2种,一是Minor GC,可以称为YGC。还有一种称为FullGC。无论是YGC或是FullGC,都会导致stop-the-world,即整个程序停止一些事务的处理,只有GC进程允许以进行垃圾回收。但是由于GC选用可达性分析算法,STW停顿时间与当前可达对象数量直接关系(越多时间越长),年轻代由于每次GC大量对象死亡,存活的是极少数,所以GC停顿时间非常短暂。
从JVM调优的角度来看,应该尽量避免发生YGC或FullGC或者使得YGC和FullGC的时间足够的短。
GC优化
GC优化归纳了两个目的:
- 一个是将转移到老年代的对象数量降到最少
- 另一个是减少Full GC的执行时间
重要的参数的含义
-Xmn 设置新生代大小
so/s1 和Eden区的比例怎么调整呢?
通过newRatio和SurvivorRatio调整0和1的比例以及新生代和老年代的比例
-XX:NewRatio 新生代(eden+2*s)和老年代(不包含永久区)的比值,例如:4,表示新生代:老年代=1:4,即新生代占整个堆的1/5
-XX:SurvivorRatio(幸存代) 设置两个Survivor区和eden的比值。例如:8,表示两个Survivor:eden=2:8,即一个Survivor占年轻代的1/10
-Xmx –Xms:指定最大堆和最小堆
-XX:+UseConcMarkSweepGC -XX:MaxTenuringThreshold=15 指定rmi调用时gc的时间间隔
优化方式
- JVM堆大小的设置,一般可以通过-Xms -Xmx限定其最小、最大值,为了防止垃圾收集器在最小、最大之间收缩堆而产生额外的时间,通常把最大、最小设置为相同的值
- 年轻代,通过 -XX:newSize -XX:MaxNewSize来设置其绝对大小。同样,为了防止年轻代的堆收缩,我们通常会把-XX:newSize -XX:MaxNewSize设置为同样大小
- 年轻代和年老代设置多大才算合理
1)更大的年轻代必然导致更小的年老代,大的年轻代会延长普通GC的周期,但会增加每次GC的时间;小的年老代会导致更频繁的Full GC
2)更小的年轻代必然导致更大年老代,小的年轻代会导致普通GC很频繁,但每次的GC时间会更短;大的年老代会减少Full GC的频率
如何选择应该依赖应用程序对象生命周期的分布情况: 如果应用存在大量的临时对象,应该选择更大的年轻代;如果存在相对较多的持久对象,年老代应该适当增大。在抉择时应该根据以下两点:
【1】本着Full GC尽量少的原则,让年老代尽量缓存常用对象,JVM的默认比例1:2也是这个道理
【2】通过观察应用一段时间,看在峰值时年老代会占多少内存,在不影响Full GC的前提下,根据实际情况加大年轻代,比如可以把比例控制在1:1,但应该给年老代至少预留1/3的增长空间 - CMS是用于老年代的回收,目标是尽量减少应用的暂停时间,减少full gc发生的几率,利用和应用程序线程并发的垃圾回收线程来标记清除年老代,以便获得更短的垃圾回收的暂停时间,提高程序的响应性。并且对MaxTenuringThreshold(生代对象撑过多少次minor gc才进入年老代的设置)设置为较高参数(默认为0)。得到了很大的性能优化。
JVM常用内存参数配置
-Xms
JVM启动时申请的初始Heap值,默认为操作系统物理内存的1/64但小于1G。默认当空余堆内存大于70%时,JVM会减小heap的大小到-Xms指定的大小,可通过-XX:MaxHeapFreeRation=来指定这个比列。Server端JVM最好将-Xms和-Xmx设为相同值,避免每次垃圾回收完成后JVM重新分配内存;开发测试机JVM可以保留默认值。(例如:-Xms4g)
-Xmx
JVM可申请的最大Heap值,默认值为物理内存的1/4但小于1G,默认当空余堆内存小于40%时,JVM会增大Heap到-Xmx指定的大小,可通过-XX:MinHeapFreeRation=来指定这个比列。最佳设值应该视物理内存大小及计算机内其他内存开销而定。(例如:-Xmx4g)
-Xss
Java每个线程的Stack大小。JDK5.0以后每个线程堆栈大小为1M,以前每个线程堆栈大小为256K。根据应用的线程所需内存大小进行调整。在相同物理内存下,减小这个值能生成更多的线程。但是操作系统对一个进程内的线程数还是有限制的,不能无限生成,经验值在3000~5000左右。
-Xmn
Java Heap Young区大小。整个堆大小=年轻代大小 + 年老代大小 + 持久代大小(相对于HotSpot 类型的虚拟机来说)。持久代一般固定大小为64m,所以增大年轻代后,将会减小年老代大小。此值对系统性能影响较大,Sun官方推荐配置为整个堆的3/8。(例如:-Xmn2g)
程序新创建的对象都是从年轻代分配内存,年轻代由Eden Space和两块相同大小的SurvivorSpace(通常又称S0和S1或From和To)构成,可通过-Xmn参数来指定年轻代的大小,也可以通过-XX:SurvivorRation来调整Eden Space及SurvivorSpace的大小。
老年代用于存放经过多次新生代GC仍然存活的对象,例如缓存对象,新建的对象也有可能直接进入老年代,主要有两种情况:1、大对象,可通过启动参数设置-XX:PretenureSizeThreshold=1024(单位为字节,默认为0)来代表超过多大时就不在新生代分配,而是直接在老年代分配。2、大的数组对象,且数组中无引用外部对象。老年代所占的内存大小为-Xmx对应的值减去-Xmn对应的值。如果在堆中没有内存完成实例分配,并且堆也无法再扩展时,将会抛出OutOfMemoryError异常。
-XX:PermSize
持久代(方法区)的初始内存大小。(例如:-XX:PermSize=64m)
-XX:MaxPermSize
持久代(方法区)的最大内存大小。(例如:-XX:MaxPermSize=512m)
-XX:+UseSerialGC
串行(SerialGC)是jvm的默认GC方式,一般适用于小型应用和单处理器,算法比较简单,GC效率也较高,但可能会给应用带来停顿。
-XX:+UseParallelGC
并行(ParallelGC)是指多个线程并行执行GC,一般适用于多处理器系统中,可以提高GC的效率,但算法复杂,系统消耗较大。(配合使用:-XX:ParallelGCThreads=8,并行收集器的线程数,此值最好配置与处理器数目相等)
-XX:+UseParNewGC
设置年轻代为并行收集,JKD5.0以上,JVM会根据系统配置自行设置,所以无需设置此值。
-XX:+UseParallelOldGC
设置年老代为并行收集,JKD6.0出现的参数选项。
-XX:+UseConcMarkSweepGC
并发(ConcMarkSweepGC)是指GC运行时,对应用程序运行几乎没有影响(也会造成停顿,不过很小而已),GC和app两者的线程在并发执行,这样可以最大限度不影响app的运行。
-XX:+UseCMSCompactAtFullCollection
在Full GC的时候,对老年代进行压缩整理。因为CMS是不会移动内存的,因此非常容易产生内存碎片。因此增加这个参数就可以在FullGC后对内存进行压缩整理,消除内存碎片。当然这个操作也有一定缺点,就是会增加CPU开销与GC时间,所以可以通过-XX:CMSFullGCsBeforeCompaction=3 这个参数来控制多少次Full GC以后进行一次碎片整理。
-XX:+CMSInitiatingOccupancyFraction=80
代表老年代使用空间达到80%后,就进行Full GC。CMS收集器在进行垃圾收集时,和应用程序一起工作,所以,不能等到老年代几乎完全被填满了再进行收集,这样会影响并发的应用线程的空间使用,从而再次触发不必要的Full GC。
-XX:+MaxTenuringThreshold=10
垃圾的最大年龄,代表对象在Survivor区经过10次复制以后才进入老年代。如果设置为0,则年轻代对象不经过Survivor区,直接进入老年代。
JVM常用命令
jinfo:可以输出并修改运行时的java 进程的opts
jps:与unix上的ps类似,用来显示本地的java进程,可以查看本地运行着几个java程序,并显示它们的进程号
jstat:一个极强的监视VM内存工具。可以用来监视VM内存内的各种堆和非堆的大小及其内存使用量
jmap:打印出某个java进程(使用pid)内存内的所有'对象'的情况(如:产生那些对象,及其数量)
jstack:查看当前java进程的堆栈状态
jconsole:一个java GUI监视工具,可以以图表化的形式显示各种数据。并可通过远程连接监视远程的服务器VM
本文详细介绍了JVM内存区域划分,包括年轻代、年老代和持久代(元空间),并深入探讨了GC机制,如MinorGC和FullGC。文章提供了JVM常用内存参数配置建议,如-Xmn、-Xms、-Xmx等,以及GC优化策略,旨在减少FullGC频率和提升应用性能。
131

被折叠的 条评论
为什么被折叠?



