Java垃圾回收器与内存分配策略

程序计数器、Java虚拟机栈、本地方法栈这3个区域都是随线程而生,随线程而灭;栈中的栈帧随着方法的进入和退出而有条不紊地执行着出栈和入栈操作 。每个栈帧分配多少内存基本上是在类结构确定下来的时候就已知的,因此这几个区域的内存分配和回收都具备确定性,在这几个区域内就不需要过多考虑回收的问题,以为方法结束或者线程结束时,内存自然就跟随着回收了 。而Java堆区和方法区则不一样,一个接口中的多个实现类需要的内存可能不一样,一个方法中的多个分支需要的内存也可能不一样,我们只有在程序处于运行期间才能知道会创建那些对象,这部分内存的分配和回收都是动态的,垃圾回收器关注的是这部分内存 。
先讲述Java堆区中的对象回收 。
判断对象是否存活

Java垃圾回收器与内存分配策略

文章插图
什么样的对象能作为GC的Root节点呢?
对象的回收
要宣告一个对象死亡,只少要经历两次标记过程:如果对象在进行可达行分析后发现没有与GC Roots相链接的引用链,那它将会被进行一次标记并且进行一次筛选,筛选的条件是此对象是否有必要执行()方法 。当对象没有覆盖()方法,或者()方法已经被虚拟机调用过,虚拟机将这两种情况都视为“没有必要执行” 。
Java垃圾回收器与内存分配策略

文章插图
对象的引用类型
说起对象的回收我们就不能不说对象的引用了,因为无论【引用计数法】判断对象的引用数量,或者【根搜索算法】判断对象的应用链是否可达,判定对象是否存活都与引用有关 。在JDK1.2之后,Java对引用的概念进行了扩充,将引用分为强引用( )、软引用(Soft )、弱引用(Weak )与虚引用( )四种,这四中引用程序依次逐渐减弱 。
方法区的回收
方法区或者是虚拟机的永久代的垃圾回收主要回收的内容有两部分:废弃的常量和无用的类 。
废弃的常量回收和Java堆中的对象回收时类似的 。
判断一个类是否是【无用的类】却比判断一个对象是否被可以被回收苛刻的多,该类需要满足同时满足一下三个条件:
垃圾回收算法标记-清除算法(Mark-Sweep)
【标记-清除】是最基础的收集算法,算法分为“标记”和“清除”两个阶段,首先标记处所有需要回收的对象,在标记完成后统一回收所被标记的对象,它的标记过程就是上边讲的对象的回收中的标记 。
特点:
Java垃圾回收器与内存分配策略

文章插图
复制算法()
为了解决效率问题,一种称为“复制”的收集算法出现了,它将可用内存按容量划分为大小相等的两块,每次只使用其中的一块,当这一块的内存用完了,就将其存活着的对象复制到另外一块上面,然后再把已使用过的内存一次清理掉 。
Java垃圾回收器与内存分配策略

文章插图
标记-整理算法(Mark )
标记-整理算法是介于【标记-清除】和【复制】之间的收集算法,标记过程任然与【标记-清除】算法一样,但后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存 。
Java垃圾回收器与内存分配策略

文章插图
分代收集算法( )
当前商业虚拟机的垃圾收集都是采用“分代收集”( )算法,这种算法并没有什么新的思想,只是根据对象存活周期的不同将内存划分为几块 。一般是把Java堆分为新生代和老年代,这样就可以根据各个年代的特点采用最适当的收集算法 。在新生代中,每次来及收集时都发现有大批对象死去,只有少量存活,那就选用复制算犯法,只需要付出少量存活对象的复制成本就可以完成收集 。而老年代中因为对象存活率高,没有额外控件对它进行分配担保,就必须使用“标记-清理”或者“标记-整理”算法来进行回收 。