JVM垃圾收集器和内存分配侧策略

来源:互联网 发布:非递归后序遍历c语言 编辑:程序博客网 时间:2024/06/01 08:06

垃圾收集器和内存分配侧策略

很多人会有疑问,为什么垃圾收集的机制已经实现了自动化,我们还需要去了解GC和内存分配的么?
回答的答案就是:
当需要排查各种内存溢出、内存泄漏问题的时候,当垃圾收集成为系统达到更能高并发量的瓶颈的时候,我们就需要对这些所谓的自动化进行调节。


如何判断对象已死?

由于堆里面放着Java对象的实例,在垃圾收集器对堆进行回收之前,首先就要确定这些对象还有哪些活着,而哪些已经死去。


1.引用计数算法
算法的原理:给对象增加一个引用计数器,每当有一个地方引用它的时候,计数器就相应的增加1,当引用失效的时候,计数器就减1,当对象的计数器为零的时候,对象就不会被引用了,但是该算法解决不了的一个问题就是:对象自己之间的引用,即使外界没有对他们相互引用,但他们的引用计数器始终不为1,由此垃圾收集器无法对这样的对象进行回收。

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();}}

虽然最后一句GC不一定能启动。通过分析可以看出,Java使用的回收策略并不是使用引用计数法。


2.根搜索算法

在主流的编程语言中都是使用根搜索算法进行判断对象是否存活。

基本思路:通过一系列名为“GC Roots”的对象作为起点,从这些节点开始向下搜索,搜索到的路径称为引用链(Reference Chain),当一个对象到“GC Roots”不可到达的时候,说明该对象是不可用的,它就会被认为是可回收的对象。

Java中,可以作为“GC Roots”对象包括一下几种:

1.虚拟机栈中引用的对象

2.方法区类静态属性引用的对象

3.方法区的常量引用的对象

4.本地方法栈中JNI的引用对象


3.关于引用

在JDK1.2之后。对引用的概念进行了改进和扩从,并将应用分为四类:强引用,软引用,弱引用,虚引用。

强引用:在程序代码中普便存在,就类似于new出来的对象,他们永远都不会被垃圾收集器回收

软引用:用来描述一些有用,但非必须的对象,对于这种对象,在系统发生内存异常之前,会把这些对象列进壳回收的范围,进行第二次的回收,在内存还是不充足的时候,才会抛出异常。

弱引用:描述非必须的对象,强度比软引用更弱一些,只能存活到下一次垃圾收集发生之前。

虚引用:我们无法通过虚引用获取一个对象的实例,为一个对象设置虚引用关联的目的就是希望这个对象被垃圾收集器收集的时候收到一个系统的通知。


回收方法区

永久代的垃圾回收有两部分的内容:废弃常量和无用的类

回收常量和Java堆的回收差不多

如何判断无用的类?

1.该类的所有实例都已经被回收

2.加载该类的类加载器已经被回收

3.该类的Class对象没有被任何地方被引用,无法通过在任何地方通过反射访问该类。


垃圾回收算法

标记-清楚算法

作为最基础的收集算法,他的实现原理和它的名字一样,分为标记和清楚阶段

缺点:效率的问题,标记和清楚的过程的效率都不高,在清除完之后,会产生大量的不连续的内存碎片,空间的碎片太多,当需要分配大对象的时候,就不得不提前触发另一次的垃圾回收。


复制算法

它的出现为了解决效率的问题

原理:它将可用的内存分为了两份,每次只使用一份,当这一块的内存用完了之后,就将还活着的对象复制到另一块去,然后把内存一次清理掉,然而就不用在继续考虑内存碎片的问题了,只要移动堆顶的指针

缺点:它的代价为内存为原来的一半

也可以将其分为三部份,两块survivor较小和一块较大eden,当回收的时候,将eden和survivor一次性的拷贝到另外一块的survivor上。


标记-整理算法

复制算法在对象的存货率高的时候,就要复制大量的对象,效率就会很低,更重要的是还会浪费50%的内容

和该名字一样,在最后的时候并不是对对象直接清理,而是将存活的对象移向一段,清理边界以外的内存


分代收集算法

该算法就是将对象的生存周期分为几块,也就是吧Java的堆分为新生代和老年代,更具不同代的特性去分配适当的垃圾收集算法

在新生代中,每次垃圾收集就会有大量的对象死去,所以适合用复制算法。老年代中,对象的存活率很高,所以可以使用“标记-整理”或者“标记-清理”算法回收


《深入理解Java虚拟机》的学习笔记