《深入理解 Java 虚拟机》学习 -- 垃圾回收算法
《深入理解 Java 虚拟机》学习 -- 垃圾回收算法
1. 说明
- 程序计数器,虚拟机栈,本地方法栈三个区域随线程而生,随线程而灭,这几个区域的内存分配和回收都具备确定性
- Java 堆和方法区这部分内存的分配和回收都是动态的,垃圾收集器所关注的是这部分内存
新生代和老年代
Java 中的堆是 JVM 所管理的最大的一块内存空间,主要用于存放各种类的实例对象。
在 Java 中,堆被划分成两个不同的区域:新生代 ( Young )、老年代 ( Old )。新生代 ( Young ) 又被划分为三个区域:Eden、From Survivor、To Survivor。
堆的内存模型大致为:
堆大小 = 新生代 + 老年代。
垃圾回收一般发生在 java 堆中。
方法区称作永久代。
新生代:
对象存活率低。
老年代:
对象存活率高。
2. 判断堆中对象是否已死(不可能再被任何途径使用的对象)算法
2.1 引用计数算法
含义:
给对象中添加一个引用计数器,每当有一个地方引用它时,计数器就加 1;当引用失效时,计数器就减 1;任何时刻计数器都为 0 的对象就是不可能再被使用的。
缺点:
很难解决对象之间的相互循环引用的问题。
举例:
下面例子中:对象 objA 和对象 objB 都有字段 instance,赋值令 objA.instance = objB 及 objB.instance = objA, 除此之外,这两个对象无任何引用,实际上这两个对象已经不可能再被访问,但是因为它们互相引用着对方,导致它们的引用计数都不为 0,于是引用计数算法无法通过 GC 收集器回收它们。
public class ReferenceCountingGC {
public Object instance = null;
private static final int _1MB = 1024 * 1024;
// 这个成员属性的唯一意义就是占点内存,以便能在GC 日志中看清楚是否被回收过
private byte[] bigSize = new byte[2 * _1MB];
public static void main(String[] args) {
ReferenceCountingGC objA = new ReferenceCountingGC();
ReferenceCountingGC objB = new ReferenceCountingGC();
objA.instance = objB;
objB.instance = objA;
objA = null;
objB = null
// 假设在这行发生 GC,那么 objA 和 objB 是否能被回收
System.gc();
}
}
注意:VM options 配置参数:-verbose:gc -XX:+PrintGCDetails
打印部分结果如下:
[GC (System.gc()) [PSYoungGen: 6772K->680K(38400K)] 6772K->680K(125952K), 0.0098335 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]
[Full GC (System.gc()) [PSYoungGen: 680K->0K(38400K)] [ParOldGen: 0K->623K(87552K)] 680K->623K(125952K), [Metaspace: 3213K->3213K(1056768K)], 0.0145286 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]
结果中可以看到 GC 日志中包含 6772K->680K,这意味这虚拟机并没有因为这两个对象互相引用就不回收它们,说明虚拟机并不是通过引用计数算法来判断对象是否存活的。
2.2. 根搜索算法(可达性分析算法)
含义:
通过一系列的名为 “GC Roots" 的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链,当一个对象到 GC Roots 没有任何引用链相连(用图论的话来说就是从 GC Roots 到这个对象不可达)时,则证明此对象时不可用的。
GC Rooot 对象:
- 虚拟机栈(栈帧的本地变量表)中的引用的对象
- 方法区中的类静态属性引用的对象
- 方法去中的常量引用的对象
- 本地方法栈中 JNI(即一般说的 Native 方法)的引用的对象
(方法区和栈中)
举例:

对象 object5,object6,object7 虽然互相有关联,但是它们到 GC Roots 是不可达的,所以它们将会被判定为是可回收的对象。
3. 垃圾收集算法
3.1 标记 - 清除算法
含义:
首先标记出所有需要回收的对象,在标记完成后统一回收掉所有被标记的对象。
缺点:
- 效率不高
- 空间碎片太多
示例:

3.2 复制算法(一般在新生代中使用)
含义:
将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉。
缺点:
将内存缩小为原来的一半,代价太高。
改进:
将 内存分为一块较大的 Eden 空间和两块较小的 Survivor 空间,每次使用 Eden 和其中的一块 Survivor 。当回收时,将 Eden 和 Survivor 中还存活着的对象一次性地拷贝到另外一块 Survivor 空间上,最后清理掉 Eden 和刚才用过的 Survivor 的空间。
示例:

3.3 标记 - 整理算法(一般在老年代中使用)
含义:
让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存。
示例:

3.4 分代收集算法
含义:
根据对象的存活周期的不同将内存划分为几块,一般是把 Java 堆分为新生代和老年代,然后根据各个年代的特点采用最适当的收集算法。
- 新生代:复制算法
- 老年代:标记 - 整理 / 标记 - 整理
现在基本都使用这种。
《深入理解 Java 虚拟机》学习 -- 垃圾回收算法的更多相关文章
- 深入理解java虚拟机【垃圾回收算法】
Java虚拟机的内存区域中,程序计数器.虚拟机栈和本地方法栈三个区域是线程私有的,随线程生而生,随线程灭而灭:栈中的栈帧随着方法的进入和退出而进行入栈和出栈操作,每个栈帧中分配多少内存基本上是在类结构 ...
- 深入理解Java虚拟机之垃圾回收篇
垃圾回收简介 Java 会对内存进行自动分配与回收管理,使上层业务更加安全,方便地使用内存实现程序逻辑.在不同的 JVM 实现及不同的回收机制中,堆内存的划分方式是不一样的. 简要地介绍下垃圾 ...
- 深入理解java虚拟机(二)-----垃圾回收
做一个java程序员很是幸福,不用管不用的对象如何被回收,但是我认为了解一下也不是坏事. 一.如何判断对象已经死亡? 在进行垃圾回收之前,第一件事肯定是判断对象是否已经死亡.1.引用计数算法给对象添加 ...
- 深入理解Java虚拟机(三)——垃圾回收策略
所谓垃圾收集器的作用就是回收内存空间中不需要了的内容,需要解决的问题是回收哪些数据,什么时候回收,怎么回收. Java虚拟机的内存分为五个部分:程序计数器.虚拟机栈.本地方法栈.堆和方法区. 其中程序 ...
- Java虚拟机之垃圾回收算法思想总结
1.引用计数法 这是个比较古老而经典的垃圾回收算法,其核心就是在对象被其他所引用的时候计数器加1,而当引用失去时减1.这个方法有非常严重的问题:无法此话有理循环引用的情况,还有就是每次进行加减操作比较 ...
- java虚拟机之垃圾回收算法
标记-清除算法: 这是最基础的,就是之前所讲的两次标记,首先标记出所有 需要回收的对象,然后进行统一清除, 这有两缺点:一是效率低,标记和清除(开启低优先级进行回收)都是低效率的.第二是空间问题,标记 ...
- 深入理解java虚拟机---3垃圾回收机制GC
本文来源于翁舒航的博客,点击即可跳转原文观看!!!(被转载或者拷贝走的内容可能缺失图片.视频等原文的内容) 若网站将链接屏蔽,可直接拷贝原文链接到地址栏跳转观看,原文链接:https://www.cn ...
- 【深入理解Java虚拟机】垃圾回收
引用计数算法 给对象加一个计数器,引用一次+1,引用时效就-1,当计数器=0时对象就不能再被使用: 实现简单,判定效率高:Java虚拟接没有使用,主要原因是很难解决对象之间循环引用问题: GC算法: ...
- 每日一问:讲讲 Java 虚拟机的垃圾回收
昨天我们用比较精简的文字讲了 Java 虚拟机结构,没看过的可以直接从这里查看: 每日一问:你了解 Java 虚拟机结构么? 今天我们必须来看看 Java 虚拟机的垃圾回收算法是怎样的.不过在开始之前 ...
随机推荐
- CentOS服务器安装部署Java环境(jdk,tomcat)
第一步:卸载openjdk 用命令 java -version,如有下面的信息说明CentOS自带OpenJdk,没安装跳过这一步: 最好还是先卸载掉openjdk,再安装oracle公司的jdk.先 ...
- [转]Nginx实现高并发的原理
Nginx 首先要明白,Nginx 采用的是多进程(单线程) & 多路IO复用模型.使用了 I/O 多路复用技术的 Nginx,就成了”并发事件驱动“的服务器. 异步非阻塞(AIO)的详解ht ...
- 1293 - Incorrect table definition; there can be only one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause
在数据库执行脚本文件时,执行到一半会遇到 这种问题: 出错处:2018-05-14 18:53:38 行号:712454 错误代码: 1293 - Incorrect table definitio ...
- pageoffice实现网页打开编辑保存word文档(基于SSM框架)
pageoffice是一款网页集成word.excel...等office工具 并不免费,但可以试用练习 SSM框架搭建过程就省略了 注意:由于谷歌/火狐升级,不支持插件嵌入,建议使用POBrowse ...
- Kubernetes-kubectl The connection to the server localhost:8080 was refused -did you specify
今天在Kubernetes的从节点上运行命令[kubectl]出现了如下错误: [root@k8snode1 kubernetes]# kubectl get pod The connection t ...
- 9-2 yum,dnf和apt
yum, CentOS: yum, dnf YUM: Yellowdog Update Modifier,rpm的前端程序,可解决软件包相关依赖性,可在多个库之间定位软件包,up2date的替代工具 ...
- Python3 Selenium自动化web测试 ==> 第七节 WebDriver高级应用 -- 浮动框中,单击选择某个关键字选项
学习目的: 了解WebDriver的高级应用 正式步骤: 测试Python3代码 # -*- coding:utf-8 -*- from selenium import webdriver from ...
- jQuery之替换节点
如果要替换节点,jQuery提供了两个方法:replaceWith()和replaceAll(). 两个方法的作用相同,只是操作颠倒了. 作用:将所有匹配的元素都替换成指定的HTML或者DOM元素.( ...
- HTML5 a标签的down属性进行图片下载
a标签中的down属性时HTML5新增的属性,此属性指示浏览器下载URL而不是导航到URL,因此将提示用户将其保存为本地文件.目前该属性的兼容性如下: 具体代码实现: /* 主要原理:利用a标签的do ...
- kernel32.dll 这个系统模块
详细解读:远程线程注入DLL到PC版微信 一.远程线程注入的原理 1.其基础是在 Windows 系统中,每个 .exe 文件在双击打开时都会加载 kernel32.dll 这个系统模块,该模块中有一 ...
