概述
可达性分析算法
通过GCRoots作为起始根节点,然后向下搜索,根据引用关系标出哪些是可回收对象,哪些是不可回收对象,GCRoots所走过的路径称为引用链,那么不可达的对象就可以被垃圾回收器回收。
可作为GCRoots的对象
1、在虚拟机栈中的局部变量所引用的对象可作为GCRoot,譬如各个线程所执行的方法中的局部变量,参数,临时变量等等。
2、元空间中静态变量所引用的对象。
3、元空间中常量所引用的对象。
4、本地方法中的所引用的对象。
5、Java虚拟机内部的引用,如class对象,一些常驻的异常对象(空指针,内存溢出等)和系统类加载器等。
6、持有同步锁的对象。
7、反映虚拟机内部情况的JMXBean,JVMTI中的注册回调,本地代码缓存等。
8、其他可能临时加入的对象。
强软弱虚四种引用类型
强引用: new Object(),使用最多的场景,当使用的时候及时内存不足了,也不会回收,只有经过可达性分析算法无法扫描到的时候才会交给垃圾回收器进行处理,否则内存不足就会OOM。
软引用: SoftReference(),空间足够的时候,不进行回收,空间不足的时候,才会进行回收。
弱引用: WeakReference(),只要是GC看到,就马上进行回收。
虚引用: PhantomReference(),等于形同虚设,就像没有引用一样。
新生代区的对象回收过程
下图为堆内存分代模型:
针对上面模型进行阐述。
创建对象的时候会将对象放入Eden区,当Eden区内存空间不足的时候会触发MinorGC,存活下来的对象移入S0区,所以Eden区的GC是非常频繁的,一般选用效率较高的算法。第二次Eden区满的时候触发MinorGC会将s0和Eden区一起进行GC,存活下来的对象进入s1区,然后s0和s1作用调换,再一次MinorGC就是原s1和Eden区参与GC,存活下来的进入原s0,如此往复复制,当分代年龄到达15(垃圾收集器不同阈值不同)之后进入老年代。这样交换的目的是防止内存碎片化,因为频繁的GC导致对象在分代区中的内存形式是不连续的,所以将其复制转移到新的分区就可以保证内存连续。内存碎片化会导致空间资源利用不充分,最直接的现象内存中明明有足够的空间,但因为不连续,所以无法存储大的对象,这样的后果是十分可怕的。
当然对象并不是分代年龄到达15就进入老年代,JVM会进行对象动态年龄判断,当剩余对象综合占比超过50%(可以通过-XX:TargetSurvivorRatio=?进行设置,默认是50)的时候,如当分代年龄到达4的时候,总占比超过了50%,那么分代年龄大于等于4的对象就会进入老年代。
对象进入老年代的几种情况
1、达到设定的分代年龄阈值的时候,可通过参数-XX:MaxTenuringThreshold来设置,默认是15(并发收集器15,CMS默认6)。
2、动态年龄判断。
3、大对象直接进入老年代,比如很长的字符串或者很长的数组或者List集合,到对象在分配内存空间的时候容易导致明明还有内存空间然后进行GC,为了获得足够的空间来存放他们,同时如果避免了GC,那么复制大对象所产生的内存消耗也是巨大的,所以此时JVM就直接跳过新生代,直接将他们存入老年代中,,可通过参数-XX:PreTenureSizeThreShoid单位为字节。注意: 这个参数只对Serial和ParNew两款新生代垃圾收集器有用,其他新生代不支持此参数。如果必须使用可以参考Serial+CMS组合使用。
4、老年代空间分配担保机制
空间分配担保机制
执行任何一次MinorGC之前都会进行判断,第一步先判断老年代剩余空间是否大于新生代对象总大小(处于极端情况,就是新生代对象全都存活了),如果大于的话就直接GC,如果小于,就第二判断,判断老年代剩余空间大小是否大于之前每一次MinorGC后进入老年代的对象的平均大小。如果大于进行GC,GC之后S区放不下,老年代也放不下就Full GC,如果小于,那就直接Full GC。如果还放不下那就OOM了。可通过参数-XX:HandlePromotionFailure来设定是否开启空间担保。
最后
以上就是大力发带为你收集整理的JVM之垃圾回收过程的全部内容,希望文章能够帮你解决JVM之垃圾回收过程所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复