GC
须要考虑的三个问题:java
在分析内存区域的时候,咱们把Java
运行时数据区分为两个部分:算法
Java
堆、方法区:因为一个接口中的多个实现类须要的内存可能不同,一个方法中的多个分支须要的内存也不同,只有在程序处于运行期间才能知道会建立哪些对象,所以这些区域的内存分配和回收是动态的。引用的定义:若是reference
类型的数据中存储的数值表明的另一块内存的起始地址,就称这块内存表明引用。 引用的分类:数组
Object a = new Object()
):只要强引用存在,垃圾回收器永远不会回收掉被引用的对象。SoftReference
):有用但并不是必须,在系统将要发生OOM
异常以前,将会把这些对象列进回收范围中进行第二次回收。WeakReference
):非必须对象,被弱引用的对象只能生存到下一次垃圾收集发生前。PhantomReference
):不会对生存时间产生影响,也没法经过虚引用来取得一个对象实例,设置虚引用的惟一目的就是能在这个对象被垃圾回收器回收时收到一个系统通知。给对象添加一个引用计数器,当有一个地方引用它时就加一,引用失效时就减一,当计数器的值为零时表示它不可用。 可是它没法解决相互循环引用问题。安全
经过一系列的称为GC Roots
的对象做为起始点,从这些节点开始向下搜索,所走过的路径称为引用链。当一个对象到GC Roots
没有任何引用链时,表示这个对象不可用,GC Roots
的类型有:线程
JNI
**引用的对象。finalize
方法对于内存回收的影响当某个对象在通过可达性分析后,发现它到GC Roots
没有任何引用链时,那么它会被第一次标记,并进行第一次筛选,筛选的结果有两种状况:code
finalize()
方法或者虚拟机已经调用过它的finalize()
方法:直接回收。F-Queue
的队列中,并在稍后由一个由虚拟机自动创建的、低优先级的Finalizer
线程去执行这个对象的finalize()
方法,如对象要在finalize
方法中拯救本身,只要从新与引用链的某个变量关联便可,那么在第二次标记时它将被移出“即将回收”的集合,不然它将被回收。这种方法代价高昂,不肯定性大,没法保证各个对象的调用顺序,所以能够忘记这个方法的存在。对象
对于方法区(HotSpot
中的永久代)主要回收两部份内容:废弃常量和无用的类。接口
abc
被放入了常量池中,可是没有任何一个String
对象引用它,那么就会被清理出常量池,常量池中其它类(接口)、方法、字段的符号引用也相似。ClassLoader
已经被回收java.lang.Class
对象没有在任何地方被引用,没法在任何地方经过发射访问该类的方法。GC
操做。概念 将可用内存划分为大小相等的两块,每次只使用其中的一块,当一块内存用完了。则触发一次GC
操做,将活着的对象复制到另外一块上,而后再把已使用的内存空间一次清理掉。队列
缺点 将内存缩小为了原来的一半。内存
如今商业虚拟机采用这种算法的改良版来实现新生代的回收 它把内存按8:1:1
分为Eden/survivor0/survivor1
三块: 须要分配内存时,首先尝试在Eden
区分配,若是Eden
区没法分配,那么尝试把活着的对象放到survivor0
中去:
若是survivor0
能够放入,那么放入以后清除Eden
区。
若是survivor0
不能够放入,那么尝试把Eden
和survivor0
的存活对象放到survivor1
中:
survivor1
能够放入,那么放入survivor1
以后清除Eden
和survivor0
,以后再把survivor1
中的对象复制到survivor0
中,保持survivor1
一直为空。survivor1
不能够放入,那么直接把它们放入到老年代中,并清除Eden
和survivor0
,这个过程也称为分配担保。适用状况 因为复制算法在对象成活率较高时,须要较多的复制操做,效率会变低,因此在老年代中不能采用该算法。
当前商业虚拟机采用的方式,根据对象存活周期的不一样将内存划分为几块,通常是新生代和老年代:
Eden/survivor0/survivor1
的分配方式。Minor GC
和Major GC/Full GC
Minor GC
:发生在新生代的垃圾回收动做,很是频繁,回收速度也较快,采用的垃圾收集器有Serial
、ParNew
、Parallel Scavenge
。Major GC/Full GC
:发生在老年代的GC
,常常伴随至少一次的Minor GC
,Major GC
的速度通常会比Minor GC
慢十倍以上,采用的垃圾收集器有CMS
、Serial Old
、Parallel Old
。对象优先在Eden
区分配 当Eden
区没有足够空间,触发一次Minor GC
。
大对象直接进入老年代 例如很长的字符串以及数组,常常出现大对象容易致使内存还有很多空间时就提早触发垃圾收集以获取足够的连续空间来“安置”它们。
长期存活的对象将进入老年代 若是Eden
区出生并进过第一次Minor GC
后,仍然存活,而且被成功复制到survivor
区中,那么对象年龄变为一,当对象在survivor
中每熬过一次Minor GC
,年龄就增长一,当年龄增长到必定程度,就会晋升到老年代中。
动态对象年龄绑定 若是survivor
空间中相同年龄全部对象大小的总和大于survivor
空间的一半,年龄大于或等于该年龄的对象就能够进入老年代,无须到达要求的年龄。
空间分配担保 在发生Minor GC
前,检查老年代最大可用连续空间是否大于新生代全部对象总空间:
大于,那么操做是安全的,不对老年代进行Full GC
。
小于,检查HandlePromotionFailure
设置值是否容许失败:
Full GC
。在这以后,由于有可能出现某次存活对象激增的状况,这种属于冒险行为,若是出现了担保失败(也就是Eden
和survivor0
的存活对象既没法放入survivor1
,也没法放入老年代的连续空间中),那么会在失败以后对老年代进行Full GC
。Full GC
。Full GC
。