Java垃圾回收机制简介

    在学习Java GC之前,需要记住一个单词:stop-the-world。它会在任何一种GC算法中发生。stop-the-world意味着JVM因为需要执行GC而停止了应用程序的执行。当stop-the-world发生时,除GC所需的线程外,所有的线程都进入等待状态,直到GC任务完成。GC优化很多时候就是减少stop-the-world的发生。

JVM GC 回收哪个区域内的垃圾

        需要注意的是,JVM,GC 只回收堆区和方法区内的对象。而栈区的数据,在超出作用域后会被JVM自动释放掉,所以它不在JVM GC的管理范围内。

JVM GC 怎么判断对象可以被回收了?

        对象没有引用

        作用域发生未捕获异常

        程序在作用域正常执行完毕

        程序执行了System.exit().

        程序发生意外终止(被杀线程等)

        在java程序中不能显示的分配和注销缓存,因为这些事情JVM都帮我们做了,那就是GC。

        有些时候我们可以将相关的对象设置成null来试图显示清除缓存。但并不是设置为null就会一定被标记为可回收。有可能会发生逃逸。

        将对象设置成null至少没什么坏处,但是使用System.gc()便不可取了 使用System.gc()的时候并不是马上执行GC操作,而是会等待一段时间,甚至不执行。而且System.gc()如果被执行,会触发Full GC,会非常影响性能。

Java GC什么时候执行?

        eden区空间不够存放新对象的时候,执行Minro GC。升到老年代的对象大于老年代剩余空间的时候执行Full GC。调优主要是减少Full GC的触发次数。可以通过NewRatio控制新生代转老年代的比例。通过MaxTenuringThreshold设置对象进入老年代的年龄阀值

按代的垃圾回收机制

        新生代(Young generation):绝大多数最新被创建的对象都会被分配到这里,由于大部分在创建后很快变得不可达,很多对象被创建在新生代。然后“消失”。对象从这个区域“消失”的过程我们称之为:Minor GC 

        老年代(old generation):对象没有变得不可达,而且从新生代周期中存活了下来,会被拷贝到这里,其区域分配的空间要比新生代多,也正是由于其相对大的空间。发生在老年代的GC次数要比新生代少得多。对象从老年代中消失的过程,称之为Major GC或者Full GC。

        

        持久代(Permanent generation)也称之为 方法区(Method area):用于保存类常量以及字符串常量。注意,这个区域不是用于存储那些从老年代存活下来的对象,这个区域也可能发生GC。发生在这个区域的GC事件也被算为 Major GC 。只不过在这个区域发生GC的条件非常严苛,必须符合以下三种条件才会被回收:

        1、所有实例被回收

        2、加载该类的ClassLoader 被回收

        3、Class 对象无法通过任何途径访问(包括反射)

JVM GC 算法讲解

1、根搜索算法

根搜索算法是从离散数学中的图论引入的,程序把所有引用关系看作一张图,从一个节点GC ROOT 开始,寻找对应的引用节点,找到这个节点后,继续寻找这个节点的引用节点。当所有的引用节点寻找完毕后,剩余的节点则被认为是没有被引用到的节点,即无用的节点。

目前Java中可以作为GC ROOT的对象有:

1、虚拟机栈中引用的对象(本地变量表)

2、方法区中静态属性引用的对象

3、方法区中常亮引用的对象

4、本地方法栈中引用的对象(Native对象)

基本所有GC算法都引用根搜索算法这种概念。

2、标记 - 清除算法

        标记-清除算法采用从根集合进行扫描,对存活的对象进行标记,标记完毕后,再扫描整个空间中未被标记的对象进行直接回收。

标记-清除算法不需要进行对象的移动,并且仅对不存活的对象进行处理,在存活的对象比较多的情况下极为高效,但由于标记-清除算法直接回收不存活的对象,并没有对还存活的对象进行整理,因此会导致内存碎片。

3、复制算法

        复制算法将内存划分为两个区间,使用此算法时,所有动态分配的对象都只能分配在其中一个区间(活动区间),而另外一个区间(空间区间)则是空闲的。

        复制算法采用从根集合扫描,将存活的对象复制到空闲区间,当扫描完毕活动区间后,会的将活动区间一次性全部回收。此时原本的空闲区间变成了活动区间。下次GC时候又会重复刚才的操作,以此循环。

        复制算法在存活对象比较少的时候,极为高效,但是带来的成本是牺牲一半的内存空间用于进行对象的移动。所以复制算法的使用场景,必须是对象的存活率非常低才行,而且最重要的是,我们需要克服50%内存的浪费。

4、标记 - 整理算法

        标记-整理算法采用 标记-清除 算法一样的方式进行对象的标记、清除,但在回收不存活的对象占用的空间后,会将所有存活的对象往左端空闲空间移动,并更新对应的指针。标记-整理 算法是在标记-清除 算法之上,又进行了对象的移动排序整理,因此成本更高,但却解决了内存碎片的问题。

JVM为了优化内存的回收,使用了分代回收的方式,对于新生代内存的回收(Minor GC)主要采用复制算法。而对于老年代的回收(Major GC),大多采用标记-整理算法




阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页