当前位置:网站首页>JVM 垃圾回收 详细学习笔记(二)
JVM 垃圾回收 详细学习笔记(二)
2022-07-07 06:28:00 【白蝶丶】
本篇博客记录个人学习jvm的过程,如有错误,敬请指正
一、判断对象是否可被回收
1.引用计数法
给对象中添加一个引用计数器,每当有一个地方引用它,计数器就加 1;当引用失效,计数器就减 1;任何时候计数器为 0 的对象就是不可能再被使用的。
这个方法实现简单,效率高,但是目前主流的虚拟机中并没有选择这个算法来管理内存,其最主要的原因是它很难解决对象之间相互循环引用的问题。如下面代码所示:除了对象 objA 和 objB 相互引用着对方之外,这两个对象之间再无任何引用。但是他们因为互相引用对方,导致它们的引用计数器都不为 0,于是引用计数算法无法通知 GC 回收器回收他们。
public class ReferenceCountingGc {
Object instance = null;
public static void main(String[] args) {
ReferenceCountingGc objA = new ReferenceCountingGc();
ReferenceCountingGc objB = new ReferenceCountingGc();
objA.instance = objB;
objB.instance = objA;
objA = null;
objB = null;
}
}
2.可达性算法
这个算法的基本思想就是通过一系列的称为 “GC Roots” 的对象作为起点,从这些节点开始向下搜索,节点所走过的路径称为引用链,当一个对象到 GC Roots 没有任何引用链相连的话,则证明此对象是不可用的,需要被回收。
下图中的 Object 6 ~ Object 10 之间虽有引用关系,但它们到 GC Roots 不可达,因此为需要被回收的对象。
常作为GC Roots的对象
- 虚拟机栈(栈帧中的本地变量表)中引用的对象(这里说的对象都是指new出来存储在堆中的对象)。
- 本地方法栈(Native 方法)中引用的对象
- 方法区中类静态属性引用的对象
- 方法区中常量引用的对象
- 所有被同步锁持有的对象
二、四种引用
引用分为强引用、软引用、弱引用、虚引用四种(引用强度逐渐减弱)
1.强引用(StrongReference)
以前我们使用的大部分引用实际上都是强引用,这是使用最普遍的引用。如果一个对象具有强引用,那就类似于必不可少的生活用品,垃圾回收器绝不会回收它。当内存空间不足,Java 虚拟机宁愿抛出 OutOfMemoryError 错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足问题。
2.软引用(SoftReference)
软引用,如果内存空间足够,垃圾回收器就不会回收它,如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可用来实现内存敏感的高速缓存。
软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收,JAVA 虚拟机就会把这个软引用加入到与之关联的引用队列中。在回收软引用所指向的对象时,软引用本身不会被清理,如果想要清理软引用,需要使用引用队列
3.弱引用(WeakReference)
弱引用与软引用的区别在于:只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。不过,由于垃圾回收器是一个优先级很低的线程, 因此不一定会很快发现那些只具有弱引用的对象。
弱引用同样可以和引用队列联合使用
4.虚引用(PhantomReference)
与其他几种引用都不同,虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收。虚引用必须和引用队列联合使用(因为被引用对象被回收后,其关联的直接内存是无法被直接释放的,因为这个直接内存不受jvm管控,所以为了回收这个直接内存就需要这个虚引用和队列配合起来使用)
软引用使用案例
package com.atguigu.test8;
import com.sun.scenario.effect.impl.sw.sse.SSEBlend_SRC_OUTPeer;
import java.io.IOException;
import java.lang.ref.SoftReference;
import java.util.ArrayList;
public class Demo1 {
public static int _4MB = 4 * 1024 * 1024;
public static void main(String[] args) throws IOException {
method1();
}
// 设置 -Xmx20m , 演示堆内存不足,
public static void method1() throws IOException {
ArrayList<byte[]> list = new ArrayList<>();
for(int i = 0; i < 5; i++) {
list.add(new byte[_4MB]);
}
System.in.read();
}
// 演示 软引用
public static void method2() throws IOException {
//使用软引用对象 list和SoftReference之间是强引用,而SoftReference和byte数组之间则是软引用
ArrayList<SoftReference<byte[]>> list = new ArrayList<>();
for(int i = 0; i < 5; i++) {
SoftReference<byte[]> ref = new SoftReference<>(new byte[_4MB]);
System.out.println(ref.get());
list.add(ref);
System.out.println(list.size());
}
System.out.println("循环结束:" + list.size());
for(SoftReference<byte[]> ref : list) {
System.out.println(ref.get());
}
}
}
我们测试前,需要先设置jvm参数,将堆内存的大小设置成20mb,并且打印GC信息
-Xmx20m -XX:+PrintGCDetails -verbose:gc
运行method1,由于list是强引用,jvm不会回收而是报出异常
运行method2,此时我们在 list 集合中存放了 软引用对象,在第五次往list中存放数据时,内存不足会触发 full gc,将软引用的对象回收
上面是没有回收软引用本身的,回收软引用得使用引用队列,修改代码如下
三、垃圾回收算法
1.标记-清除算法
该算法分为“标记”和“清除”阶段:首先标记出所有不需要回收的对象,在标记完成后统一回收掉所有没有被标记的对象。它是最基础的收集算法,后续的算法都是对其不足进行改进得到。这种垃圾收集算法会产生内存碎片
下图的蓝色是标记的,无需回收的对象
2.标记-复制算法
标记过程仍然与“标记-清除”算法一样,但后续步骤不是直接对可回收对象回收,而是让所有存活的对象向一端移动,然后直接清理掉端边界以外的内存,效率较低
3. 标记-复制算法
为了解决效率问题,“标记-复制”收集算法出现了。它可以将内存分为大小相同的两块,每次使用其中的一块。当这一块的内存使用完后,就将还存活的对象复制到另一块去,然后再把使用的空间一次清理掉。这样就使每次的内存回收都是对内存区间的一半进行回收,缺点是内存需要更多(双倍)
4.分代收集算法
当前虚拟机的垃圾收集都采用分代收集算法,它根据对象存活周期的不同将内存分为几块。一般将 java 堆分为新生代和老年代,这样就可以根据各个年代的特点选择合适的垃圾收集算法。
比如在新生代中,每次收集都会有大量对象死去,所以可以选择”标记-复制“算法,只需要付出少量对象的复制成本就可以完成每次垃圾收集。而老年代的对象存活几率是比较高的,而且没有额外的空间对它进行分配担保,所以我们必须选择“标记-清除”或“标记-整理”算法进行垃圾收集。
下面是分代收集算法的具体步骤
1.新建的对象进入伊甸园
2.当伊甸园中的内存满了时,触发MirrorGC,会使用复制算法,将存活对象复制进To区,并且寿命加1
3.将To区和From区交换(就是复制算法),始终保持To区为空
下面那个2改成1(尴尬)
4.周而复始,当有对象年龄达到15(不是绝对的)对象还存活,就会进入老年代区
5.如果新生代老年代中的内存都满了,就会先触发Minor GC,再触发Full GC,扫描新生代和老年代中所有不再使用的对象并回收;
边栏推荐
- OpenGL帧缓冲
- Image segmentation in opencv
- Interpretation of MySQL optimization principle
- Markdown编辑器Editor.md插件的使用
- Golang etcdv3 reports an error. The attribute in grpc does not exist
- Calculation s=1+12+123+1234+12345 C language
- OpenGL frame buffer
- MAC OSX php dyld: Library not loaded: /usr/local/xxxx. dylib
- Nanjing commercial housing sales enabled electronic contracts, and Junzi sign assisted in the online signing and filing of housing transactions
- Simple use of Xray
猜你喜欢
Data analysis methodology and previous experience summary 2 [notes dry goods]
Greenplum 6.x version change record common manual
串口实验——简单数据收发
数字三角形模型 AcWing 275. 传纸条
面板显示技术:LCD与OLED
NCS Chengdu Xindian interview experience
Simple use of Xray
Calf problem
Panel display technology: LCD and OLED
Greenplum6.x搭建_安装
随机推荐
H3C VXLAN配置
Un salaire annuel de 50 W Ali P8 vous montrera comment passer du test
Routing information protocol rip
模拟卷Leetcode【普通】1567. 乘积为正数的最长子数组长度
Count the number of words in the string c language
[wechat applet: cache operation]
Uniapp wechat applet monitoring network
let const
Recommended by Alibaba P8, the test coverage tool - Jacobo is very practical
LeetCode 715. Range module
JS operation
Calf problem
QT charts use (rewrite qchartview to realize some custom functions)
Markdown编辑器Editor.md插件的使用
Common operating commands of Linux
C语言指针(特别篇)
年薪50w阿里P8亲自下场,教你如何从测试进阶
Selenium automation integration, eight years of testing experience, soft test engineer, an article to teach you
【ChaosBlade:根据标签删除POD、Pod 域名访问异常场景、Pod 文件系统 I/O 故障场景】
Why choose cloud native database