java垃圾回收浅析

Wesley13
• 阅读 668

摘要

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

垃圾回收主要需要考虑的3个问题:

1、什么时候回收;

2、哪些对象需要回收;

3、如何回收。

运行时数据区域

java垃圾回收浅析

程序计数器(Program Conuter Register)

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

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

也就是通常所说的栈区,它描述的是Java方法执行的内存模型,每个方法被执行的时候都创建一个栈帧(Stack Frame),用于存储局部变量表、操作数栈、动态链接、方法出口等。每个方法被调用到完成,相当于一个栈帧在虚拟机栈中从入栈到出栈的过程。此区域也是线程私有的内存,可能抛出两种异常:

  • 如果线程请求的栈深度大于虚拟机允许的深度将抛出StackOverflowError;
  • 如果虚拟机栈可以动态的扩展,扩展到无法动态的申请到足够的内存时会抛出OOM异常。

本地方法栈(Native Method Stacks)

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

堆区(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。

如何回收?

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

标记-清除算法。

java垃圾回收浅析

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

复制算法。

java垃圾回收浅析

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

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

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

标记整理算法。

java垃圾回收浅析

分代收集算法。

java垃圾回收浅析

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

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

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

哪些对象进入老年代?

A.大对象。

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

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

D.如果survivor空间不能容纳Eden中存活的对象。由于担保机制会进入老年代。如果survivor中的对象存活很多,担保失败,那么会进行一次Full GC。

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

点赞
收藏
评论区
推荐文章
待兔 待兔
5个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
灯灯灯灯 灯灯灯灯
3年前
【垃圾回收】全面解析,内含面试题及图文详解!!
垃圾回收概述和相关算法1.Java和C语言的区别,就在于垃圾收集技术和内存动态分配上,C语言没有垃圾收集技术,需要程序员手动的收集。2.垃圾收集,不是Java语言的伴生产物。早在1960年,第一门开始使用内存动态分配和垃圾收集技术的Lisp语言诞生。3.关于垃圾收集有三个经典问题:哪些内存需要回收?什么时候
Wesley13 Wesley13
3年前
java中的GC和内存泄漏
java中的GC1.GC是什么?为什么要有GC? GC是垃圾回收的意思。是指JVM清理不再使用的对象释放内存。垃圾回收可以有效的防止内存泄露,有效的使用可以使用的内存.2\.需要GC的内存区域垃圾回收区域:主要针对无用堆对象回
Wesley13 Wesley13
3年前
Java系列笔记
Java垃圾回收概况  JavaGC(GarbageCollection,垃圾收集,垃圾回收)机制,是Java与C/C的主要区别之一,作为Java开发者,一般不需要专门编写内存回收和垃圾清理代码,对内存泄露和溢出的问题,也不需要像C程序员那样战战兢兢。这是因为在Java虚拟机中,存在自动内存管理和垃圾清扫机制。概括地说,该机制对JVM(J
Wesley13 Wesley13
3年前
Java 内存区域和GC机制
Java垃圾回收概况  JavaGC(GarbageCollection,垃圾收集,垃圾回收)机制,是Java与C/C的主要区别之一,作为Java开发者,一般不需要专门编写内存回收和垃圾清理代码,对内存泄露和溢出的问题,也不需要像C程序员那样战战兢兢。这是因为在Java虚拟机中,存在自动内存管理和垃圾清扫机制。概括地说,该机制对JVM
Wesley13 Wesley13
3年前
Java虚拟机垃圾回收相关知识点全梳理(下)
一、前言上一篇文章《Java虚拟机垃圾回收相关知识点全梳理(上)(https://www.oschina.net/action/GoToLink?urlhttps%3A%2F%2Fwww.luozhou.top%2F2019%2F04%2F28%2Fjvmgc01%2F)》我整理分享了JVM运行时数据区域的划分,垃圾判定算法以及垃圾回
Wesley13 Wesley13
3年前
Java虚拟机垃圾回收相关知识点全梳理(上)
一、前言笔者最近在复习JVM的知识,本着记录分享的精神,整理下学习Java虚拟机垃圾回收相关知识点,由于整个垃圾回收内容比较多,我将整理成上下两篇文章去分享,上篇我会主要分享Java虚拟机的运行时数据区域划分,垃圾回收算法。下篇文章主要分享Java虚拟机的垃圾回收器以及一些虚拟机调优建议。二、运行时数据区Java虚拟机
Wesley13 Wesley13
3年前
Java 虚拟机垃圾收集机制详解
本文摘自深入理解Java虚拟机第三版垃圾收集发生的区域之前我们介绍过Java内存运行时区域的各个部分,其中程序计数器、虚拟机栈、本地方法栈三个区域随线程共存亡。栈中的每一个栈帧分配多少内存基本上在类结构确定下来时就已知,因此这几个区域的内存分配和回收都具有确定性,不需要考虑如何回收的问题,当方法结束或线程结
Stella981 Stella981
3年前
JVM系列(二) — Java垃圾收集介绍
这篇文章主要从以下几个方面介绍垃圾收集的相关知识  一、判断对象是否已死  二、主流垃圾收集算法  三、内存分配与回收策略  本章节主要从以下几个思考点着手介绍垃圾回收的相关知识:哪些内存需要回收?什么时候回收?如何回收?这也是经典的学习一个知识点的3h方法:what?when?how?上一个章节已经介绍jvm运行时数据区的内存分布,
Stella981 Stella981
3年前
JVM的GC算法总结
Java程序在运行过程中,会产生大量的内存垃圾(一些没有引用指向的内存对象都属于内存垃圾,因为这些对象已经失去标记,程序用不了它们了,对程序而言它们已经废弃),为了确保程序运行时的性能,java虚拟机在程序运行的过程中不断地进行自动的垃圾回收(GC),这就是我们的垃圾回收机制,关于垃圾回收我总结了一下几种:标记–清除算法(MarkSweep)