1.JVM的分代模型:年轻代(创建和使用完立马回收的对象放在里面)、老年代(创建之后长期存在的对象放在立马,比方static变量)、永久代
1.1大部分的对象都是优先在年轻代分配内存的,新生代里分配大量的对象,使用完之后没有再次被引用了,且新生代已经占用了大部分内存,当再次要分配新的对象时,发现新生代内存不够时,就会触发一次垃圾回收。如果有些变量成功躲过了每一次垃圾回收达到一定次数之后,会被转移到堆内存得老年代中。
-Xms :Java堆内存的大小 -Xmx:Java堆内存最大大小 -Xmn:Java堆内存中的新生代大小,扣除新生代剩下未老年代内存大小
-XX:PermSize:永久代大小 -XX:MaxPermSize:永久代最大大小 -Xss:每个线程的栈内存大小
例如:“-Xms3072M -Xmx3072M -Xmn2048M -Xss1M -XX:PermSize=256M -XX:MaxPermSize=256M -XX:SurvivorRatio=8”
1.2垃圾回收算法
1.2.1 可达算法 只要一个对象被局部变量引用了,就可以说它有一个GC root,不会被回收了。方法的局部变量和类的静态变量是GC Roots
1.2.2 复制算法 将内存分为两个区,其中一个区用来动态分配给对象,另外一个区空闲,当活动区内存满时,触发gc,将存活的对象转移到空闲区。这种做法的缺点是浪费内存空间,只有一半可用,且内存碎片化。
1.2.3 优化复制算法 将新生代内存分为Eden区和两个Survivor区,分配比例为8:1:1,Eden区用来分配新建对象使用,如果内存满了触发GC,将活着的对象转移到一块空闲的Survivor区,清空Eden区,当再次触发垃圾回收Eden区时,将Eden区和一块Survivor区里的存活对象转移到另外一块Survivor,如此往复。 当Survivor中存活对象所占内存大于当前Survivor的一半时,此时大于这批对象年龄的对象直接进入老年区。当GC后存活对象大于Survivor内存时,直接进入老年区 ,进去老年区之前需要先检测下当前老年区可用内存是否满足当前Eden区对象大小,如果不够会触发一次Full GC,之后如果还不够,则产生OOM异常。 另外也可以根据参数设定(-XX:PretenureSizeThreshold),当对象大于某个值时直接进去老年代。
1.2.4 老年代标记算法 记录每一个存活对象,整理到一块连续内存空间,然后清理其它不需要的对象,防止出现内存碎片。
总结:在Minor GC之前,先检查下老年代是否有足够内存存放所有新生代对象,如果足够,进行minor gc,进入Survivor区,如果该区大小不足够,进去老年区
在Minor GC之前,先检查下老年代是否有足够内存存放所有新生代对象,之后会看一个“-XX:-HandlePromotionFailure=true”(空间分配担保)的参数是否设置了,下一步判断之前每次进去老年区的平均内存大小,如果判断失败,则进行一次full gc,如果前面两个条件都符合,则进行minor gc
2.垃圾回收器
2.1ParNew是新生代多线程垃圾回收器
2.2CMS老年代垃圾回收器(标记算法,将垃圾对象标记,并一次性回收掉,这样会产生内存碎片,如果碎片太多导致没有足够可用的连续空间放入新对象,就会触发一次Full GC)
2.2.1初始标记 (标记所有GC Roots引用的对象,会有stw)
2.2.2并发标记(垃圾回收现成和工作现成同时运行,对老年代的所有对象进行GC root追踪)
2.2.3重新标记(经过并发标记后,由于工作线程在不停的工作产生新对象,有些对象可能变成垃圾对象,进行重新标记,会有stw)
2.2.4并发处理(清理掉之前标记的垃圾对象,占用CPU资源)
”-XX:CMSInitiatingOccupancyFaction” 参数用来设置老年代占用多少比例的时候触发CMS垃圾回收,如果在CMS垃圾回收期间,工作线程创建的对象不能在老年代放下,则会产生Concurrent Mode Failure,说明内存不够了,这时会用“Serial Old”进行垃圾回收
”-XX:+UseCMSCompactAtFullCollection”:Full GC之后STW,进行碎片整理,默认打开
“-XX:CMSFullGCsBeforeCompaction”:执行多少次Full GC之后进行碎片整理,默认是(0)每次FGC之后内存碎片整理
“-XX:CMSInitiatingOccupancyFaction”:老年代已使用内存大于该参数设定值,则触发FGC
“-XX:MaxTenuringThreshold”参数:躲过设置参数默认15次垃圾回收后自动升入老年代
”-XX:PretenureSizeThreshold”参数:大对象可以直接进入老年代,比如1M(-XX:PretenureSizeThreshold=1M)
-XX:+UseParNewGC 参数:指定新生代垃圾回收器为Parnew
-XX:+UseConcMarkSweepGC”:指定老年代垃圾回收器为CMS,如(-XX:PretenureSizeThreshold=1M -XX:+UseParNewGC -XX:+UseConcMarkSweepGC”)
“-XX:HandlePromotionFailure”选项(1.7以后废弃):只要老年代的连续空间大于新生代对象的总大小或者历次晋升到老年代的对象的平均大小就进行MinorGC
,否则FullGC
查看垃圾回收器命令:java -XX:+PrintCommandLineFlags -version
3.Full GC触发时机:(1.老年代可用内存小于新生代全部对象大小 2.老年代可用内存小于历次平均进入老年代对象大小 3.ygc后存活对象大于Survivor,进入老年代且老年代内存不够)
4.优化的前提是合理分配内存空间,合理预估内存空间的使用。