JAVA的垃圾收集器与内存分配策略【一篇文章直接看懂】

内存动态分配和垃圾收集技术是JAVA和C++之间最大的区别之一
垃圾收集( ,GC)只办三件事:
对于对象回收的方法 引用计数法:
每处引用时+1,引用失效时-1,但是主流的Java虚拟机里面都没有选用引用计数算法来管理内存 。
比如很难解决对象之间相互循环引用的问题
objA.=objB ;objB.=objA
objA = null; objB = null
后,objA和objB未被回收
可达性分析算法
主流的商用语言(Java\C#\Lisp)通过可达性分析( )进行判断 。
基本思路就是通过一系列称为“GC Roots”的根对象作为起始节点集,从这些节点开始,根据引用关系向下搜索,搜索过程所走过的路径称为“引用链”( Chain),如果某个对象到GC Roots间没有任何引用链相连,或者用图论的话来说就是从GC Roots到这个对象不可达时,则证明此对象是不可能再被使用的 。
可以作为GC Roots的对象:
引用概念的修改
判定对象是否存活都和“引用”离不开关系,但是过去的只有被引用和未被引用放在当今过于狭隘了 。
譬如我们希望能描述一类对象:当内存空间还足够时,能保留在内存之中,如果内存空
间在进行垃圾收集后仍然非常紧张,那就可以抛弃这些对象——很多系统的缓存功能都符合这样的应
用场景 。
JDK1.2后队引用进行了补充
对于对象的消亡判断
在可达性判断中,若判断为不可达的对象时,那么是处于缓刑阶段 。宣告一个对象死亡需要两次标记过程
在可达性分析后,发现没有与GC ROOT相连的引用链,则会被第一次标记对象是否有必要执行()方法 。若没有覆盖该方法或该方法已经被虚拟机调用过,则视为不需要执行 。若判断为需要执行,则将对象放置到名为F-Queue的队列中,然后由优先级低的线程去执行 。如果在()中重新与引用链上的任何一个对象建立关联则不会被回收,否则被回收 。回收方法区
主要回收两部分的内容:废弃的常量和不再使用的类型
判断废弃的常量:假如一个字符串“java”曾经进入常量池中,但是当前系统又没有任何一个字符串对象的值是“java”
判断一个类型是否属于“不再被使用的类“:
·该类所有的实例都已经被回收,也就是Java堆中不存在该类及其任何派生子类的实例 。
·加载该类的类加载器已经被回收,这个条件除非是经过精心设计的可替换类加载器的场景,如OSGi、JSP的重加载等,否则通常是很难达成的 。
·该类对应的java.lang.Class对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法 。
Java虚拟机被允许对满足上述三个条件的无用类进行回收,这里说的仅仅是“被允许”,而并不是和对象一样,没有引用了就必然会回收 。
垃圾收集算法
大致可分为 引用计数式垃圾收集(GC)和 追踪式垃圾收集( GC)
以下介绍的均为主流Java虚拟机中使用的追踪式垃圾收集的范畴
分代收集理论
由上诉的前两条理论产生的设计原则::收集器应该将Java堆划分出不同的区域,然后将回收对象依据其年龄(年龄即对象熬过垃圾收集过程的次数)分配到不同的区域之中存储 。
若一个区域的大多数对象都是朝生夕灭的,则只关注如何保留少量存货 。若剩下的都是难以消亡的,则集中放在一起,使用较低的频率来回收这个区域,兼顾了时间开销和内存的空间 。
如今,设计者将JAVA堆划分为新生代和老年代的两个区域 。但是,对象不是孤立的,对象之间会存在跨代引用,由此,引出了跨代引用假说,即存在相引用关系的两个对象,是应该倾向于同时生存或者同时消亡的 。