愿君学长松,慎勿作桃李。这篇文章主要讲述JVM系列 从一到掌握JVM系列之垃圾回收算法相关的知识,希望能为你提供帮助。
【JVM系列 从一到掌握JVM系列之垃圾回收算法】
标记阶段:引用计数算法垃圾标记阶段:对象存活判断
方式一:引用计数算法
循环引用
每次赋值都需要更新计数器,伴随着加法和减法操作,这增加了时间开销。
当p的指针断开的时候,内部的引用形成一个循环,这就是循环引用,从而造成内存泄漏。
举例
/**
* -XX:+PrintGCDetails
* 证明:java使用的不是引用计数算法
* @author shkstart
* @create 2020 下午 2:38
*/
public class RefCountGC
//这个成员属性唯一的作用就是占用一点内存
private byte[] bigSize = new byte[5 * 1024 * 1024];
//5MB
Object reference = null;
public static void main(String[] args)
RefCountGC obj1 = new RefCountGC();
RefCountGC obj2 = new RefCountGC();
obj1.reference = obj2;
obj2.reference = obj1;
obj1 = null;
obj2 = null;
//显式的执行垃圾回收行为
//这里发生GC,obj1和obj2能否被回收?
System.gc();
try
Thread.sleep(1000000);
catch (InterruptedException e)
e.printStackTrace();
通过 ??-XX:+PrintGCDetails?
? 输出详细信息
[GC (System.gc()) [PSYoungGen: 15497K->
696K(76288K)] 15497K->
704K(251392K), 0.0013045 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[Full GC (System.gc()) [PSYoungGen: 696K->
0K(76288K)] [ParOldGen: 8K->
624K(175104K)] 704K->
624K(251392K), [Metaspace: 3274K->
3274K(1056768K)], 0.0043467 secs] [Times: user=0.05 sys=0.00, real=0.00 secs]
Heap
PSYoungGentotal 76288K, used 655K [0x000000076ad80000, 0x0000000770280000, 0x00000007c0000000)
eden space 65536K, 1% used [0x000000076ad80000,0x000000076ae23ee8,0x000000076ed80000)
from space 10752K, 0% used [0x000000076ed80000,0x000000076ed80000,0x000000076f800000)
tospace 10752K, 0% used [0x000000076f800000,0x000000076f800000,0x0000000770280000)
ParOldGentotal 175104K, used 624K [0x00000006c0800000, 0x00000006cb300000, 0x000000076ad80000)
object space 175104K, 0% used [0x00000006c0800000,0x00000006c089c178,0x00000006cb300000)
Metaspaceused 3281K, capacity 4496K, committed 4864K, reserved 1056768K
class spaceused 359K, capacity 388K, committed 512K, reserved 1048576K
我们能够看到,上述进行了GC收集的行为,将上述的新生代中的两个对象都进行回收了
PSYoungGen: 15490K->
808K(76288K)] 15490K->
816K(251392K)
如果使用引用计数算法,那么这两个对象将会无法回收。而现在两个对象被回收了,说明Java使用的不是引用计数算法来进行标记的。
引用计数算法,是很多语言的资源回收选择,例如因人工智能而更加火热的 python,它更是同时支持引用计数和垃圾收集机制。
具体哪种最优是要看场景的,业界有大规模实践中仅保留引用计数机制,以提高吞吐量的尝试。
Java 并没有选择引用计数,是因为其存在一个基本的难题,也就是很难处理循环引用关系。
Python 如何解决循环引用?
手动解除:很好理解,就是在合适的时机,解除引用关系。
使用弱引用 weakref,weakref 是 Python 提供的标准库,旨在解决循环引用。
推荐阅读
- 从里到外,手把手一起把JVM虚拟机整体结构与对象内存分配解析摸透透的,简单易懂!
- 我在工地抬杠,抬到了我梦寐以求的996!TvT~
- 为什么你的设计模式用的就是比别人垃圾()
- Java编程练习题,基础不牢地动山摇!看看着50道你会几道!
- Java从入门到放弃 · ArrayList集合小练习
- 重中之重!!面对JVM时,栈帧之局部变量表的重要性不用我来说吧!
- 老生常谈NIO,我们再来聊一聊关于NIO的故事和一些用法!
- 现在后端都在用什么数据库存储数据(以及数据库的架构!)
- DTMO直播预告丨ChunJun 2022年开源规划&支持异构数据源