垃圾收集器和内存分配侧策略java
不少人会有疑问,为何垃圾收集的机制已经实现了自动化,咱们还须要去了解GC和内存分配的么?因为堆里面放着Java对象的实例,在垃圾收集器对堆进行回收以前,首先就要肯定这些对象还有哪些活着,而哪些已经死去。算法
package com.GC; public class ReferenceCountingGC { public Object instance = null; private static final int _1MB = 1024*1024; private byte[] bigsize = new byte[2*_1MB]; public static void main(String[] args) { ReferenceCountingGC a = new ReferenceCountingGC(); ReferenceCountingGC b = new ReferenceCountingGC(); a.instance = a; b.instance = b; a = null; b = null; System.gc(); } }
2.根搜索算法编程
在主流的编程语言中都是使用根搜索算法进行判断对象是否存活。并发
基本思路:经过一系列名为“GC Roots”的对象做为起点,从这些节点开始向下搜索,搜索到的路径称为引用链(Reference Chain),当一个对象到“GC Roots”不可到达的时候,说明该对象是不可用的,它就会被认为是可回收的对象。编程语言
Java中,能够做为“GC Roots”对象包括一下几种:高并发
1.虚拟机栈中引用的对象学习
2.方法区类静态属性引用的对象spa
3.方法区的常量引用的对象指针
4.本地方法栈中JNI的引用对象code
3.关于引用
在JDK1.2以后。对引用的概念进行了改进和扩从,并将应用分为四类:强引用,软引用,弱引用,虚引用。
强引用:在程序代码中普便存在,就相似于new出来的对象,他们永远都不会被垃圾收集器回收
软引用:用来描述一些有用,但非必须的对象,对于这种对象,在系统发生内存异常以前,会把这些对象列进壳回收的范围,进行第二次的回收,在内存仍是不充足的时候,才会抛出异常。
弱引用:描述非必须的对象,强度比软引用更弱一些,只能存活到下一次垃圾收集发生以前。
虚引用:咱们没法经过虚引用获取一个对象的实例,为一个对象设置虚引用关联的目的就是但愿这个对象被垃圾收集器收集的时候收到一个系统的通知。
回收方法区
永久代的垃圾回收有两部分的内容:废弃常量和无用的类
回收常量和Java堆的回收差很少
如何判断无用的类?
1.该类的全部实例都已经被回收
2.加载该类的类加载器已经被回收
3.该类的Class对象没有被任何地方被引用,没法经过在任何地方经过反射访问该类。
垃圾回收算法
标记-清楚算法
做为最基础的收集算法,他的实现原理和它的名字同样,分为标记和清楚阶段
缺点:效率的问题,标记和清楚的过程的效率都不高,在清除完以后,会产生大量的不连续的内存碎片,空间的碎片太多,当须要分配大对象的时候,就不得不提早触发另外一次的垃圾回收。
复制算法
它的出现为了解决效率的问题
原理:它将可用的内存分为了两份,每次只使用一份,当这一块的内存用完了以后,就将还活着的对象复制到另外一块去,而后把内存一次清理掉,然而就不用在继续考虑内存碎片的问题了,只要移动堆顶的指针
缺点:它的代价为内存为原来的一半
也能够将其分为三部份,两块survivor较小和一块较大eden,当回收的时候,将eden和survivor一次性的拷贝到另一块的survivor上。
标记-整理算法
复制算法在对象的存货率高的时候,就要复制大量的对象,效率就会很低,更重要的是还会浪费50%的内容
和该名字同样,在最后的时候并非对对象直接清理,而是将存活的对象移向一段,清理边界之外的内存
分代收集算法
该算法就是将对象的生存周期分为几块,也就是吧Java的堆分为新生代和老年代,更具不一样代的特性去分配适当的垃圾收集算法
在新生代中,每次垃圾收集就会有大量的对象死去,因此适合用复制算法。老年代中,对象的存活率很高,因此能够使用“标记-整理”或者“标记-清理”算法回收
《深刻理解Java虚拟机》的学习笔记