【JVM】垃圾回收算法
垃圾回收机制
- 垃圾回收
- 判断对象是否存活的算法
- 1、引用计数法
- 2、可达性分析
- 常用垃圾收集(GC)算法
- 1、标记-清除算法
- 2、复制算法
- 3、标记-整理算法(或叫压缩算法)
- 分代收集算法
- (1)新生代(复制算法)
- (2)老年代(标记整理或标记清除算法)
- (3)永久代
- 何时触发GC(垃圾收集)?
- 如何避免频繁的GC?
垃圾回收
垃圾回收(Garbage Collecting ,GC),顾名思义就是释放垃圾占用的空间,防止内存泄露。有效的使用可以使用的内存,对内存堆中已经死亡或者长时间没有使用的对象进行清除和回收。垃圾回收机制就是java虚拟机(JVM)垃圾回收器提供的一种用于在空闲时间不定时回收无任何对象引用的对象占据内存空间的一种机制。
判断对象是否存活的算法
1、引用计数法
引用计数法的做法是为每个对象添加一个引用计数器,用来统计指向该对象的引用个数,当有地方引用该对象时计数器加1,当引用失效时计数器减1,用对象计数器是否为0来判断对象是否可被回收。一旦某个对象的引用计数器为0,则说明该对象已经死亡,便可以回收了。
(1)具体实现
如果有一个引用,被赋值为某一对象,那么该对象的引用计数器 + 1 。如果一个指向某一对象的引用,被赋值为其他值,那么将该对象的引用计数器 - 1 。也就是说,我们需要截获所有的引用更新操作,并且相应的增减目标对象的引用计数器。
(2)缺点
除了需要额外的空间来存储计数器,以及繁琐的更新操作,引用计数法还有一个重大的漏洞——无法处理循环引用对象。
举个例子,假设对象 a 与 b 相互引用,除此之外没有其他引用指向 a 或者 b 。在这种情况下,a 和 b 实际上已经死了,但由于它们的引用计数器皆不为0,所以这些循环引用对象所占据的空间将不可回收,从而造成了内存泄露。
2、可达性分析
目前Java虚拟机的主流垃圾回收器采取的是可达性分析算法。可达性分析算法的实质在于将一系列GC Roots 作为初始的存活对象合集(live set),然后从该合集出发,探索所有能够被该集合引用到的对象,并将其加入到该集合中,这个过程也称之为标记(Mark)。最终,未被探索到的对象便是死亡的,是可以回收的。
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200707181157852.png =500px)
可达性分析可以解决引用计数法不能解决的循环引用问题。还拿上面例子说明,即便对象 a 和 b 相互引用,只要从GC Roots出发无法到达 a 或者 b ,那么可达性分析便不会将它们加入存活对象合集中。
(1)GC Roots
暂时理解为由堆外指向堆内的引用,一般来说,GC Roots包括以下几种:
- Java方法栈帧中的局部变量
- 已加载类的静态变量
- JNI handles
- 已启动且未停止的Java线程
(2)缺点
在多线程环境下,其他线程可能会更新已经访问过的对象中的引用,从而造成误报(将引用设置为null),或者漏报(将引用设置为未被访问过的对象)。
如果发生了误报,Java虚拟机最多损失了部分垃圾回收的机会。漏报比较麻烦,因为垃圾回收器可能回收事实上仍被引用的对象内存。一旦从原引用访问已经被回收了的对象,则很有可能会直接导致Java虚拟机崩溃。
常用垃圾收集(GC)算法
1、标记-清除算法
分为两个步骤:第一就是标记,也就是标记所有需要回收的对象;第二就是清理,标记完成后进行统一的回收带有标记的对象占据的内存空间。这个算法效率不高,而且在标记清除之后会产生大量的内存不连续的内存碎片,当程序运行过程中需要分配较大对象时,无法找到足够的连续内存而造成内存空间浪费。
缺点:
(1)造成内存碎片。由于Java虚拟机的堆中对象必须是连续分布的,因此可能出现总空闲内存足够,但是无法分配的极端情况。
(2)分配效率低。如果是一块连续的内存空间,可以通过指针加法来做分配。对于空闲列表,Java虚拟机则需要逐个访问列表中的项,来查找能够放入新建对象的空闲内存。
2、复制算法
复制算法是将内容容量划分成大小相等的两块,每次只使用其中的一块。当一块内存用完之后,就将还存活的对象复制到另一块上面,然后再把已使用的内存空间一次性清理。这样使得每次都对其中一块进行内存回收,内存分配时也就不用考虑内存碎片等复杂情况,只是这种算法的代价就是将内存缩小为原来的一半了。
3、标记-整理算法(或叫压缩算法)
标记整理算法和标记清除算法很相似,显著的区别是:标记清除算法只对不存活的对象进行处理,剩余存活对象不做任何处理,所以造成了内存碎片的问题;而标记整理算法对不存活的对象进行清除,还对存活的对象进行重新整理,因此不会产生内存不连续的现象。
分代收集算法
分代收集算法是目前大部分JVM的垃圾收集器采用的算法。其核心思想是根据对象存活的生命周期将内存划分为若干个不同的区域。然后根据不同的区域采用合适的收集算法,它本身并不是一个新的收集算法。在jdk1.7之前,对JVM分为三个区域:新生代,老年代,永久代。
(1)新生代(复制算法)
新生代的目标就是尽可能快速的收集掉那些生命周期较短的对象,一般情况下新生成的或者朝生夕亡的对象一般都是首先存放在新生代里。
因为新生代会频繁的进行GC清理,所以采用的是复制算法,先标记出存活的实例,然后清除掉无用实例,将存活的实例根据年龄(每个实例被经历一次GC后年龄会加1)拷贝到不同的年龄代。
(2)老年代(标记整理或标记清除算法)
老年代一般存放的是一些生命周期较长的对象,比如是新生代中经历了N次垃圾回收后仍然存活的对象都进入了老年代。
这块内存区域一般大于年轻代,GC发生的次数也比年轻代要少。
在老年代中因为对象存活率较高,没有额外的空间对它分配担保,就必须使用标记清除或标记整理。
(3)永久代
永久代主要存放静态文件,如java类,方法等,永久代对垃圾回收没有显著影响。
方法区主要回收的内容有:废弃的常量,无用的类,对于废弃的常量可以通过引用的可达性分析判断,但是对于无用类需要同时满足以下三个条件:
1、该类的所有实例都已经被回收了
2、加载该类的ClassLoader已经被回收了
3、该类对于的java.lang.Class 对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。
何时触发GC(垃圾收集)?
- 执行System.gc()的时候
- 老年代空间不足,一次Full GC之后,然后不足 会触发Java.outofmemoryError.java heap space
- 永久代空间不足,永生代或者永久代,java.outofMemory PerGen Space
- minor 之后 survivor 放不下,放入老年代,老年代也放不下,触发FullGC,或者新生代有对象放入老年代,老年代放不下,触发FullGC
- 新生代晋升为老年代的时候,老年代剩余空间低于新生代晋升为老年代的速率,会触发老年代回收
- new 一个大对象,新生代放不下,直接到老年代,空间不够,触发FullGC
如何避免频繁的GC?
- 不要频繁的new对象
- 不要显式的调用system.gc()
- 不要用String+ ,使用StringBuilder
- 不要使用Long ,Integer,尽量使用基本类型
- 少用静态变量,不会回收
- 可以使用null进行回收
【JVM】垃圾回收算法相关推荐
- JVM 垃圾回收算法 -可达性分析算法!!!高频面试!!!
前言:学习JVM,那么不可避免的要去了解JVM相关的垃圾回收算法,本文只是讲了讲了可达性分析算法,至于标记-清除.标记-复制,标记-整理,分代收集等等算法,会在近两天的文章中陆续更新出来. 很喜欢一句 ...
- java jvm垃圾回收算法_深入理解JVM虚拟机2:JVM垃圾回收基本原理和算法
本文转自互联网,侵删 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 喜欢的话麻烦点下Star哈 文章将同步到我的个人博客: www.how ...
- JVM垃圾回收算法与原理详解
垃圾回收 参考文档 GC参考手册-Java版 理解Java的强引用.软引用.弱引用和虚引用 JVM系列(五) - JVM垃圾回收算法 如何判断对象可以回收 引用计数法 参考文章 Java JVM的引用 ...
- jvm垃圾回收算法和垃圾回收器
垃圾回收算法 jvm垃圾回收算法包括复制算法.标记清楚算法和标记整理算法,它们都基于分代收集理论.所谓分代收集理论,可以理解为jvm根据对象的生命年龄将他们分在不同的内存模块,也就是熟知的新生代和老年 ...
- jvm垃圾回收算法详解
前言 相比C语言,JVM虚拟机一个优势体现在对对象的垃圾回收上,JVM有一套完整的垃圾回收算法,可以对程序运行时产生的垃圾对象进行及时的回收,以便释放JVM相应区域的内存空间,确保程序稳定高效的运行, ...
- JVM垃圾回收算法及垃圾回收器
目录 一.垃圾回收GC (Garbage Collection) 1.1 垃圾回收介绍: 1.2 如何判断对象是否存活(被使用) 1.2.1 引用计数算法(已经废弃) 1.2.2 可达性分析 二.垃 ...
- 记录JVM垃圾回收算法
垃圾回收算法可以分为三类,都基于标记-清除(复制)算法: Serial算法(单线程) 并行算法 并发算法 JVM会根据机器的硬件配置对每个内存代选择适合的回收算法,比如,如果机器多于1个核,会对年轻代 ...
- JVM垃圾回收算法 总结及汇总
先看一眼JVM虚拟机运行时的内存模型: 1.方法区 Perm(永久代.非堆) 2.虚拟机栈 3.本地方法栈 (Native方法) 4.堆 5.程序计数器 1 首先的问题是:jvm如何知道那些对象需要回 ...
- Java基础:JVM垃圾回收算法
众所周知,Java的垃圾回收是不需要程序员去手动操控的,而是由JVM去完成.本文介绍JVM进行垃圾回收的各种算法. 1. 如何确定某个对象是垃圾 1.1. 引用计数法 1.2. 可达性分析 2. 典型 ...
- JVM 垃圾回收算法及回收器详解
本文主要讲述JVM中几种常见的垃圾回收算法和相关的垃圾回收器,以及常见的和GC相关的性能调优参数. GC Roots 我们先来了解一下在Java中是如何判断一个对象的生死的,有些语言比如Python是 ...
最新文章
- css 命名规范 BEM
- 关于MVP模式的一些讨论文章
- cocos对象池的使用
- 【拥抱大厂系列】几个面试官常问的垃圾回收器,下次面试就拿这篇文章怼回去!
- Java 9,Jigsaw,JPMS和模块:个人探索
- [20141121]无法通过powershell读取sql server性能计数器问题
- java lbp_LBP特征提取原理及代码实现
- 我的单片机固件被人给破解了
- 2022年3月23日蜻蜓q旗舰版v1.2.1重大性能更新-优化加载列表数据方式-更加丝滑-后端增加goeasy
- IPSec:IKEv2协议详解
- x^n mod 1003(快速求解法)
- Selenium自动化测试入门(基于Python)
- 网络通讯学习(3)-----UDP通讯(仅了解)
- Java 读取word文件的页数
- 常见的markdown语法总结(不断更新中......)
- Python校实训第一天----分支语句之星座查询
- 七月在线笔记之推荐系统
- POJ 3107 Godfather(树形DP(找重心))
- 题目1022:游船出租 2007年浙江大学计算机及软件工程研究生机试真题
- Could not extract response: no suitable HttpMessageConverter found for response type [class java.lan
热门文章
- CUDA内存管理一文理清|参加CUDA线上训练营
- 生死单元技术!如何在abaqus焊接仿真中的应用
- Android Studio发生AVD Pixel_XL_API_30 is already running报错,无手机界面问题
- pdf口令安全性破解
- html调整垂直居中,html元素垂直居中的几种方法
- 30句感悟人生的格言名言
- Selenium | 页面跳转后无法定位到元素,怎么破?
- 《启示录》给了我多少启示?--------《启示录》读后感
- mysql百万数据建索引时间_mysql百万的数据快速创建索引
- 干货|6个牛逼的基于Vue.js的后台控制面板,接私活必备