11 JVM 垃圾回收(上)
引用计数法和可达性分析
垃圾回收,就是将已经分配出去的,但却不在使用的内存回收回来,以便再次分配。在 Java 虚拟机语境下,垃圾指的是死亡的对象所占据的堆空间。下面就总结一下如何如何辨别一个对象是否死亡。
引用计数法:为每一个对象添加一个引用计数器,用来统计指向该对象的引用个数。如果某个对象的引用计数器为 0,则说明该对象已经死亡,便可以被回收了。
通过引用计数法来标记对象的死亡和存活的过程中,我们需要截获所有引用更新操作,并且相应的增减目标对象的引用计数器。这种方式除了需要额外的空间来存储计数器,以及繁琐的更新操作,引用计数法还有一个重大的漏洞:无法处理循环引用对象。比如:对象 A,B 互相引用,但是除此之外没有其他引用指向 A 或者 B。这种情况下 A,B 其实已经死亡,但是因为存在引用,所以不会被垃圾回收,造成内存泄露。
可达性分析:将一系列 GC Roots 作为初始存活对象集合,然后从该集合出发,探索所有能够被该集合引用的对象,并将其加入到该集合中,这个过程就是标记。标记的对象就是存活对象,未标记到的就是死亡的对象。
什么是 GC Roots 呢?可以暂时理解为由堆外指向堆内的引用,常见的有以下几种:
1:Java 方法栈帧中的局部变量
2:已加载的类的静态变量
3:JNI handles
4:已启动且未停止的 Java 线程
可达性分析解决了引用计数法无法检测循环引用的问题,但是本身也有自己的问题需要解决。比如在多线程环境下,其他线程可能会更新已经访问过的对象中的引用,从而造成误报(将引用设置为 null)或者漏报(将引用设置为未被访问过的对象)。
误报:导致新产生的垃圾对象未被回收。
漏报:导致原程序访问已经被回收的对象,可能导致 Java 虚拟机直接崩溃。
Stop-the-world 以及安全点
为了解决上述问题,在 Java 虚拟机里,采用 Stop-the-world 方式,停止其他非垃圾回收线程的工作,直到完成垃圾回收。这也造就了垃圾回收所谓的暂停时间 GC pause。
Java 虚拟机中的 Stop-the-world 是通过安全点(safepoint)机制来实现的。当 Java 虚拟机收到 Stop-the-world 请求时,它便会等待所有的线程到达安全点,才允许请求 Stop-the-world 的线程进行独占的工作。
安全点的作用不是让线程停下,而是找到让线程找到一个稳定的执行状态。在这个状态下,Java 虚拟机的堆栈不会发生变化。这样,垃圾回收期便能够安全地执行可行性分析。
垃圾回收的三种方式
第一种:清除。
把死亡对象所占据的内存标记为空闲内存,并记录在一个空闲列表中。当需要创建对象时,内存管理块便会从该空闲列表中寻找空闲内存,并划分给新建对象。
这种方式简单明了,但是却有两个缺点。第一:造成内存碎片。由于 Java 虚拟机的堆中对象必须是连续分布的,因此可能出现总空闲内存足够,但是无法分配的极端情况。第二:分配效率低。如果是连续的内存空间,可以通过指针加法来做分配。而对于这种空闲列表,Java 虚拟机则需要住个访问列表中的项,来查找能够存放入新建对象的空闲内存。
第二种:压缩。
把存活的对象聚集到内存区域的起始位置,从而留下一段连续的内存空间。这种做法解决了内存碎片化的问题,但是代价却是压缩算法的性能开销。
第三种:复制。
内存区域分为两等分,分别用两个指针 from 和 to 来维护,并且只是用 from 指针指向的内存区域来分配内存。当发生垃圾回收时,把存活的对象复制到 to 指针指向的内存区域,并且交换 from 指针和 to 指针的内容。这种方法同样解决了内存碎片化的问题,但是堆空间的使用效率及其地下,只用到了一半。
问答
Q:可达性分析a与b互为引用,这不是死循环了吗,为什么能被回收的
因为可达性分析只标记可达的,如果a和b都不可达,那么可达性分析标记不到,就当成垃圾回收了。
Q:对于为什么需要stw机制的解释还是有的困惑。假如一个对象已经被标记为垃圾了,其它线程怎么还会有机会引用它呢?就算通过stw,把它标记并回收了,那想引用它的线程重新恢复执行了会发生什么?
GC标记的是活着的(能够被引用到的)对象,剩下的是垃圾。如果没有STW,其他线程在垃圾回收过程中产生了垃圾(某对象不再被引用),那么会被漏掉。
总结
本文创作灵感来源于 极客时间 郑雨迪老师的《深入拆解 Java 虚拟机》课程,通过课后反思以及借鉴各位学友的发言总结,现整理出自己的知识架构,以便日后温故知新,查漏补缺。
关注本人公众号,第一时间获取最新文章发布,每日更新一篇技术文章。

11 JVM 垃圾回收(上)的更多相关文章
- JDK分析工具&JVM垃圾回收(转)
转自:http://blog.163.com/itjin45@126/blog/static/10510751320144201519454/ 官方手册:http://docs.oracle.com/ ...
- JVM基础系列第8讲:JVM 垃圾回收机制
在第 6 讲中我们说到 Java 虚拟机的内存结构,提到了这部分的规范其实是由<Java 虚拟机规范>指定的,每个 Java 虚拟机可能都有不同的实现.其实涉及到 Java 虚拟机的内存, ...
- Java虚拟机垃圾回收:内存分配与回收策略 方法区垃圾回收 以及 JVM垃圾回收的调优方法
在<Java对象在Java虚拟机中的创建过程>了解到对象创建的内存分配,在<Java内存区域 JVM运行时数据区>中了解到各数据区有些什么特点.以及相关参数的调整,在<J ...
- JVM垃圾回收?看这一篇就够了!
深入理解JVM垃圾回收机制 1.垃圾回收需要解决的问题及解决的办法总览 1.如何判定对象为垃圾对象 引用计数法 可达性分析法 2.如何回收 回收策略 标记-清除算法 复制算法 标记-整理算法 分带收集 ...
- JVM内存管理和JVM垃圾回收机制
JVM内存管理和JVM垃圾回收机制(1) 这里向大家描述一下JVM学习笔记之JVM内存管理和JVM垃圾回收的概念,JVM内存结构由堆.栈.本地方法栈.方法区等部分组成,另外JVM分别对新生代和旧生代采 ...
- 老李分享:jvm垃圾回收
老李分享:jvm垃圾回收 poptest是国内唯一一家培养测试开发工程师的培训机构,以学员能胜任自动化测试,性能测试,测试工具开发等工作为目标.如果对课程感兴趣,请大家咨询qq:908821478 ...
- jvm - 垃圾回收
jvm - 垃圾回收 注意 : 本系列文章为学习系列,部分内容会取自相关书籍或者网络资源,在文章中间和末尾处会有标注 垃圾回收的意义 它使得java程序员不再时时刻刻的关注内存管理方面的工作. 垃圾回 ...
- JVM垃圾回收机制概述
JVM垃圾回收机制概述 1.定义 是指JVM用于释放那些不再使用的对象所占用的内存. 2.方式 2.1引用计数(早期) 当引用程序创建引用以及引用超出范围时,JVM必须适当增减引用数.当某个对象的引用 ...
- JVM垃圾回收算法解析
JVM垃圾回收算法解析 标记-清除算法 该算法为最基础的算法.它分为标记和清除两个阶段,首先标记出需要回收的对象,在标记结束后,统一回收.该算法存在两个问题:一是效率问题,标记和清除过程效率都不太高, ...
随机推荐
- Sqlserver计算本年度工作日
--@StartDate 本年度第一天 --@EndDate 本年度最后一天 , ) , DATEADD(yy, , , )) IF EXISTS ( SELECT * FROM tempdb..sy ...
- C# asp.net mvc 注解验证
看代码,看注解,看懂了单词,没看懂意思. 今日只能专攻一下这项特性. 1.Remote 在看这个例子的时候 ,看了JsonResult 以及 JsonRequestBehavior.AllowGet解 ...
- Hadoop完全分布式集群环境搭建
1. 在Apache官网下载Hadoop 下载地址:http://hadoop.apache.org/releases.html 选择对应版本的二进制文件进行下载 2.解压配置 以hadoop-2.6 ...
- 外网访问FTP服务,解决只能以POST模式访问Filezilla的问题
在内网可以正常使用PASV,但是在外网不行,导致数据传输慢或者根本连接不了,在FlashFXP中通过日志,找到了解决方法解决方法1.在Filezilla——Edit——Settings——Passiv ...
- shell脚本,awk结合正则来打印文件里面的内容。
文件内容如下:key1abc d key2 1.想得到如下结果: abc d 2.想得到如下结果: key1key2
- java算法面试题:有数组a[n],用java代码将数组元素顺序颠倒
package com.swift; import java.util.ArrayList; import java.util.Collections; import java.util.List; ...
- runtime消息转发机制
Objective-C 扩展了 C 语言,并加入了面向对象特性和 Smalltalk 式的消息传递机制.而这个扩展的核心是一个用 C 和 编译语言 写的 Runtime 库.它是 Objective- ...
- java实现单链表归并算法
public class LinkMergeSort {static int number=0;public static void main(String[] args) {int[] a = {1 ...
- Ansible学习 安装
对于运维人员来说,自动化工具是日常工作中比不可少的.Ansible是一个很好的自动化工具. Ansible默认使用SSH协议管理机器,在管理主机上安装Ansible,管理主机和被管理主机只要安装了py ...
- ZendFramework-2.4 源代码 - 关于MVC - View层 - 视图渲染器、视图插件管理器
<?php // 1. 视图渲染器 class PhpRenderer implements Renderer, TreeRendererInterface { /** * 插件管理器 */ p ...