垃圾回收深刻分析

摘要

垃圾回收和内存分配相关,先了解运行时数据区域的划分及各个区域的做用。java

垃圾回收主要须要考虑的3个问题:算法

一、何时回收;数组

二、哪些对象须要回收;spa

三、如何回收。线程

运行时数据区域

 

程序计数器(Program Conuter Register)

        程序计数器是一块较小的内存空间,它是当前线程执行字节码的行号指示器,字节码解释工做器就是经过改变这个计数器的值来选取下一条须要执行的指令。它是线程私有的内存,也是惟一一个没有OOM异常的区域。3d

Java虚拟机栈区(Java Virtual Machine Stacks)

        也就是一般所说的栈区,它描述的是Java方法执行的内存模型,每一个方法被执行的时候都建立一个栈帧(Stack Frame),用于存储局部变量表、操做数栈、动态连接、方法出口等。每一个方法被调用到完成,至关于一个栈帧在虚拟机栈中从入栈到出栈的过程。此区域也是线程私有的内存,可能抛出两种异常:若是线程请求的栈深度大于虚拟机容许的深度将抛出StackOverflowError;若是虚拟机栈能够动态的扩展,扩展到没法动态的申请到足够的内存时会抛出OOM异常。对象

本地方法栈(Native Method Stacks)

        本地方法栈与虚拟机栈发挥的做用很是类似,区别就是虚拟机栈为虚拟机执行Java方法,本地方法栈则是为虚拟机使用到的Native方法服务。blog

堆区(Heap)

        全部对象实例和数组都在堆区上分配,堆区是GC主要管理的区域。堆区还能够细分为新生代、老年代,新生代还分为一个Eden区和两个Survivor区。此块内存为全部线程共享区域,当堆中没有足够内存完成实例分配时会抛出OOM异常。内存

方法区(Method Area)

       方法区也是全部线程共享区,用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译后的代码等数据。GC在这个区域不多出现,这个区域内存回收的目标主要是对常量池的回收和类型的卸载,回收的内存比较少,因此也有称这个区域为永久代(Permanent Generation)的。当方法区没法知足内存分配时抛出OOM异常。运行时常量池是方法区的一部分,用于存放编译期生成的各类字面量和符号引用。资源

哪些对象须要回收?

引用计数法

给对象中添加一个引用计数器,每当有一个地方引用它时,计数器值就加1 ;当引用失效时,计数器值就减1 ;任什么时候刻计数器都为0 的对象就是不可能再被使用的。引用计数算法(Reference Counting)的实现简单,断定效率也很高,在大部分状况下它都是一个不错的算法,可是Java 语言中没有选用引用计数算法来管理内存,其中最主要的缘由是它很难解决对象之间的相互循环引用的问题。

根搜索算法

    这个算法的基本思路就是经过一系列的名为“GC Roots”的对象做为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链(Reference Chain),当一个对象到GC Roots 没有任何引用链相连(用图论的话来讲就是从GC Roots 到这个对象不可达)时,则证实此对象是不可用的。在Java 语言里,可做为GC Roots 的对象包括下面几种:

  1. 虚拟机栈(栈帧中的本地变量表)中的引用的对象。
  2. 方法区中的类静态属性引用的对象。
  3. 方法区中的常量引用的对象。
  4.  本地方法栈中JNI(即通常说的Native 方法)的引用的对象。

何时回收?

GC常常发生的区域是堆区,堆区还能够细分为新生代、老年代,新生代还分为一个Eden区和两个Survivor区。

A.对象优先在Eden中分配,当Eden中没有足够空间时,虚拟机将发生一次Minor GC,Minor GC很是频繁,并且速度也很快;

 B.Full GC,发生在老年代的GC,当老年代没有足够的空间时即发生Full GC,发生Full GC通常都会有一次Minor GC。

C.发生Minor GC时,虚拟机会检测以前每次晋升到老年代的平均大小是否大于老年代的剩余空间大小,若是大于,则进行一次Full GC,若是小于,则查看是否容许担保失败,若是容许,那只会进行一次Minor GC,若是不容许,则改成进行一次Full GC。

如何回收?

先看看经常使用的垃圾回收算法。

标记-清除算法。

 

缺点:标记、清除的效率都很低;标记清除后致使不连续空间。

复制算法。

 

优势:存活率低时高效,回收后空间连续。

缺点:内存分红大小相同的两块,资源浪费。存活率高的状况下复制的对象多,效率低。

HotSpot内存分配:Eden :Survivor:Survivor = 8:1:1。每次只有10%的内存是可能被浪费的。

标记整理算法。

 

分代收集算法。

 

根据对象的存活周期将内存分为新生代和老年代。

新生代中的对象都是朝生夕死的对象,老年代中的对象相对比较稳定。

新生代和老年代采用不一样的收集算法。新生代的特色对象存活率很低(复制算法);老年代的特色对象存活率高,没有额外的空间进行分配担保(标记整理算法)。

哪些对象进入老年代?

A.大对象。

B.每次Eden进行MinorGC后对象年龄加1进入survivor,对象年龄达到15时进入老年代。

C.若是Survivor空间中相同年龄全部对象大小的总和大于survivor空间的一半,年龄大于等于该年龄的对象就直接进入老年代。

D.若是survivor空间不能容纳Eden中存活的对象。因为担保机制会进入老年代。若是survivor中的对象存活不少,担保失败,那么会进行一次Full GC。

 

总结:本文参考《深刻理解java虚拟机》进行总结,若有不妥之处请读者批评教导。

相关文章
相关标签/搜索