JAVA GC 机制详解_JAVA_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > JAVA > JAVA GC 机制详解

JAVA GC 机制详解

 2015/4/19 0:26:38  mdxdjh2  程序员俱乐部  我要评论(0)
  • 摘要:最近整理GC相关原理,发现各种文章都太乱,于是整理一份自己看得懂,不废话,具体如下。GC主要用于管理JVM的堆区,所以先来介绍一下JVM的内存分配。1、程序计数器(ProgramConuterRegister)程序计数器是一块较小的内存空间,它是当前线程执行字节码的行号指示器,字节码解释工作器就是通过改变这个计数器的值来选取下一条需要执行的指令。它是线程私有的内存,也是唯一一个没有OOM异常的区域。2、Java虚拟机栈区(JavaVirtualMachineStacks)也就是通常所说的栈区
  • 标签:详解 Java

最近整理GC相关原理,发现各种文章都太乱,于是整理一份自己看得懂,不废话,具体如下。

?

GC主要用于管理JVM的堆区,所以先来介绍一下JVM的内存分配。

?

?1、程序计数器(Program Conuter Register)

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

??????? 2、Java虚拟机栈区(Java Virtual Machine Stacks)

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

??????? 3、本地方法栈(Native Method Stacks)

??????? 本地方法栈与虚拟机栈发挥的作用非常相似,区别就是虚拟机栈为虚拟机执行Java方法,本地方法栈则是为虚拟机使用到的Native方法服务。

??????? 4、堆区(Heap)

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

??????? 5、方法区(Method Area)

?????? 方法区也是所有线程共享区,用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译后的代码等数据。GC在这个区域很少出现,这个区域内存回收的目标主要是对常量池的回收和类型的卸载,回收的内存比较少,所以也有称这个区域为永久代(Permanent Generation)的。当方法区无法满足内存分配时抛出OOM异常。

??????? 6、运行时常量池(Runtime Constant Pool)

??????? 运行时常量池是方法区的一部分,用于存放编译期生成的各种字面量和符号引用。

?

针对GC的原理机制,主要搞清楚下面三个问题。

1、什么时候回收?

2、哪些需要回收?

3、怎么回收?

?

1、什么时候回收?


上面提到GC主要管理的是堆区,堆区主要分为新生代老年代。大概解释一下这两个区域。

新生代:分为一个Eden和两个Survivor区。新new的对象都放在这里,很快消亡。

老年代:新new的大对象直接丢到这里(为了避免在Eden区和两个Survivor区发生大量的内存拷贝),其余就是在新生代多次回收没被干掉过来变成老家伙的对象了。

?

①对象优先分配到新生代的Eden区,当不够空间的时候进行一次Minor GC,清理频率很高。

②Full GC发生在老年代,当不够空间的时候进行一次Full GC,伴随着也会进行一次Minor GC。

③进行Minor GC时,会判断每次变成晋升到老年代的对象平均值是否大于老年代剩余空间,如果大于,则进行一次Full GC,如果小于就会去判断HandlePromotionFailure设置是否允许担保失败,如果允许,则进行Minor GC,不允许则改为Full GC。

?

2、哪些需要回收?

?

为了下面内容更好理解,首先来了解一下finalize方法。

?

什么是finalize()方法?

每次进行GC之前系统都会调用一次finalize()方法,用以清理所有活动并且释放资源。

?

什么时候调用finalize()方法?

1、GC调用之前,例如运行System.gc();(调用System.gc()只是建议JVM去执行,是否执行还得JVM去判断)

2、程序退出时,每个对象都会调用finalzie

3、显式调用finalize

?

-----------------------------------------------------------------------------------------------------------------------------------

引用根搜索算法(GC ROOT Tracing),当一个对象没有任何引用连接的时候,则说明对象不可达,即对象不可用,这个时候就需要进行GC清理。

判断对象是否可达的依据是有没必要执行finalize()方法。如果finalize()方法没有被覆盖或者已经被系统调用过一次了(每个对象生命周期内只能调用一次),则被不可达,需要进行GC清理,否则进行自救,恢复引用连接。

---------------------------------------------------------------------------------------------------------------------------------

3、怎么回收?

?

不同区域回收算法不同。

新生代:停止-复制。

老年代:标记-清理、标记-整理。

?

新生代:新生代分为一个Eden区、两个Survivor区(Survivor0、Survivor1)。回收时先把Eden存活对象复制到Survivor0区,清空Eden区,当Survivor0区满了以后,把Eden和Survivor0区的存活对象复制到Survivor1区,清空Eden区和Survivor0区,之后交换Survivor0和Survivor1区,保持Survivor1区是空的,如此往复。

?

老年代:这两个没什么说的,字面理解。

?

?

发表评论
用户名: 匿名