十二、垃圾回收篇
作者:互联网
一、概述
关于垃圾收集有主个经典问题:
- 哪些内存需要回收?
- 什么时候回收?
- 如何回收?
1、什么是垃圾?
垃圾是指在运行程序中没有任何指针指向的对象,这个对象就是需要被回收的垃圾。
如果不及时对内存中的垃圾进行清理,那么,这些垃圾对象所占的内存空间会一直保留到应用程序结束,被保留的空间无法被其他对象使用。甚至可能导致内存溢出。
2、为什么需要GC?
- 对于高级语言来说,一个基本认知是如果不进行垃圾回收,内存迟早都会被消耗完,因为不断地分配内存空间而不进行回收,就好像不停地生产生活垃圾而从来不打扫一样。
- 除了释放没用的对象,垃圾回收也可以清除内存里的记录碎片。碎片整理将所占用的堆内存移到堆的一端,以便JVM将整理出的内存分配给新的对象。
- 随着应用程序所应付的业务越来越庞大、复杂,用户越来越多,没有GC就不能保证应用程序的正常进行。而经常造成STW的GC又跟不上实际的需求,所以才会不断地尝试对GC进行优化。
3、Java中垃圾回收的重点区域是?
垃圾回收器只作用在堆和方法区。其中,Java堆是垃圾收集器的工作重点。
从次数上讲:
- 频繁收集Young区
- 较少吸集Old区
- 基本不动方法区(元空间)
二、垃圾回收算法
1、垃圾标记阶段算法
在堆里存放着几乎所有的java对象实例,在GC 执行垃圾回收之前,首先需要区分出内存中哪些是存活对象,哪些是已经死亡的对象。只有被标记为己经死亡的对象,GC才会在执行垃圾回收时,释放掉其所占用的内存空间,因此这个过程我们可以称为垃圾标记阶段。
(1)引用计数算法
引用计数算法(Reference Counting)比较简单,对每个对象保存一个整型的引用计数器属性。用于记录对象被引用的情况。
原理:
对于一个对象A,只要有任何一个对象引用了A,则A的引用计数器就加1,当引用失效时,引用计数器就减1。只要对象A的引用计数器的值为0,即表示对象A不可能再被使用,可进行回收。
优点:
- 实现简单,垃圾对象便于辨识;判定效率高,回收没有延迟性。
缺点:
- 它需要单独的字段存储计数器,这样的做法增加了存储空间的开销。
- 每次赋值都需要更新计数器,伴随着加法和减法操作,这增加了时间开销。
- (核心缺点)引用计数器有一个严重的问题,即无法处理循环引用的情况。这是一条致命缺陷,导致在Java的垃圾回收器中没有使用这类算法。
Java并没有选择引用计数,是因为其存在一个基本的难题,也就是很难处理循环引用关系。
(2)可达性分析算法(或根搜索算法、追踪性垃圾收集)
相对于引用计数算法而言,可达性分析算法不仅同样具备实现简单和执行高效等特点,更重要的是该算法可以有效地解决在引用计数算法中循环引用的问题,防止内存泄漏的发生。
相较于引用计数算法,这里的可达性分析就是Java、C#选择的。这种类型的垃圾收集通常也叫作追踪性垃圾收集(Tracing Garbage collection)。
原理:
其原理简单来说,就是将对象及其引用关系看作一个图,选定活动的对象作为GC Roots,然后跟踪引用链条,如果一个对象和GC Roots之间不可达,也就是不存在引用链条,那么即可认为是可回收对象。
思路:
- 可达性分析算法是以根对象集合(GC Roots)为起始点,按照从上至下的方式搜索被根对象集合所连接的目标对象是否可达。
- 使用可达性分析算法后,内存中的存活对象都会被根对象集合直接或间接连接着,搜索所走过的路径称为引用链(Reference Chain)
- 如果目标对象没有任何引用链相连,则是不可达的,就意味着该对象己经死亡,可以标记为垃圾对象。
- 在可达性分析算法中,只有能够被根对象集合直接或者间接连接的对象才是存活对象。
优点:
实现简单,执行高效 ,有效的解决循环引用的问题,防止内存泄漏。
GC Roots:
在Java 语言中, GC Roots 包括以下几类元素:
- 虚拟机栈中引用的对象。比如:各个线程被调用的方法中使用到的参数、局部变量等。
- 方法区中类静态属性引用的对象
- 方法区中常量池中的引用
- 所有被同步锁synchronized持有的对象
- Java虚拟机内部的引用。基本数据类型对应的Class对象,一些常驻的异常对象(如:NullPointerException、OutOfMemoryError),系统类加载器。
- 本地方法栈内JNI(通常说的本地方法)引用的对象
- 反映java虚拟机内部情况的JMXBean、JVMTI中注册的回调、本地代码缓存等。
小技巧:由于Root 采用栈方式存放变量和指针,所以如果一个指针,它保存了堆内存里面的对象,但是自己又不存放在堆内存里面,那它就是一个Root 。
注意点:
如果要使用可达性分析算法来判断内存是否可回收,那么分析工作必须在一个能保障一致性的快照中进行。这点不满足的话分析结果的准确性就无法保证。
这点也是导致GC进行时必须“stop The world”的一个重要原因。即使是号称(几乎)不会发生停顿的CMS收集器中,枚举根节点时也是必须要停顿的。
2、垃圾清除阶段算法
(1)标记-清除算法
(2)复制算法
(3)标记-压缩算法
(4)分代收集算法
(5)人增量收集算法
(6)分区算法
三、相关概念
四、垃圾回收器
五、分析GC日志
标签:对象,内存,十二,回收,算法,GC,引用,垃圾 来源: https://www.cnblogs.com/shiblog/p/15956179.html