深入理解JAVA虚拟机《二》
对象、内存回收和垃圾收集算法
一、引用计数算法(不可靠)
- 现在很多比较普遍的判断对象是否存活的算法就是引用计数算法,其大概原理是:给对象中添加一个引用计数器,每当有一个地方引用它时,计数器值就加1;当引用失效时,计数器值就减1,;任何时刻计数器为0的对象就是不可能再使用。
- 目前很多公司都有用到应用这个算法,客观地说,引用计数算法实现简单,判定效率也高,大多数情况下都是一个不错的算法。但是,至少主流的Java虚拟机里面没有选用引用计数算法来管理内存,最主要的原因就是它很难解决对象之间相互循环引用的问题。 举个例子,对象objA 和 objB 都有字段 instance,赋值令 objA.instance = objB; 及 objB.instance = objA; 除此之外,这两个对象再无任何引用,实际上这两个对象已经不可能再被访问,但是他们之间因为互相引用着对方,导致它们的引用计数都不为0,所有引用计算法无法通知GC收集器回收他们。
二、可达性分析算法
- 目前的主流商用程序语言(Java、C#等)的主流实现中,都是称通过可达性分析来判断对象是否存活的。这个算法的基本思想就是:通过一系列的称为 “GC Roots” 的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链,当一个对象到 GC Roots 没有任何引用的时链相连的时候(这个时候,就是 GC Roots 到这个对象不可达),则可证明此对象是不可用的,即可通知 GC 收集器进行回收。 如下图所示,对象object 5、object 6、object7 虽然互相有关联,但是它们到 GC Roots是不可达的,所有被判定为可回收对象。

三、引用
在 JDK 1.2 之后,Java对引用的概念进行了补充,将引用分为 强引用、软引用、弱引用、虚引用这4种引用,这4种引用强度逐渐减弱。
- 强引用:程序代码之中普遍存在的,类似 “Object obj = new Object() ” 这类的引用,只要强引用还存在,垃圾回收器永远不会回收被引用的对象。
- 软引用:用来描述一些还有用但并非必需的对象。对于软引用关联着的对象,在系统将要发生OOM异常之前,将会把这些对象列进回收范围之中进行第二次回收。通俗地讲,内存足够,不进行回收,内存不足,进行回收。在 JDK 1.2 之中,提供了 SoftReference 类来实现软引用。
- 弱引用:用来描述非必需的对象,强度比软引用更弱一些,被弱引用关联的对象只能生存到下一次垃圾回收收集发生之前。当垃圾收集器工作时,无论当前内存是否足够,都会回收掉只被弱引用关联的对象。一旦被扫描到,就会被回收。在 JDK 1.2 之中,提供了 WeakReference 类来实现弱引用。
- 虚引用:最弱的一种引用关系,一个对象是否有虚引用的存在,完全不会对其生存时间构成影响,也无法通过虚引用来取得一个对象实例。随时随刻,都会被回收。为一个对象设置虚引用关联的唯一目的就是能在这个对象被收集器回收时收到一个系统通知。在 JDK 1.2 之中,提供了 PhantomReference 类来实现虚引用。
四、对象的死亡
在可达性分析算法判定了一个对象不可达即被回收的时候,还不能判定该对象死亡;要真正宣告一个对象死亡,至少要经历两次标记过程:如果对象在进行可达性分析后发现没有与GC Roots 相连接的引用链,那它将会第一次标记并且进行一次筛选,筛选的条件是此对象是否有必要执行 finalize() 方法。当对象没有覆盖finalize() 方法,或finalize() 方法已经被虚拟机调用过,虚拟机将这两种情况都视为“没有必要执行”。 如果这个对象被判定为有必要执行 finalize() 方法,那么这个对象将会放置在一个叫做 F - Queue的队列之中,并在稍后由一个由虚拟机自动建立的、低优先级的 Finalizer 线程去执行它。
五、回收方法区
永久代的垃圾收集主要回收两部分内容:废弃常量和无用的类。回收废弃常量和回收Java堆中的对象非常相似。以常量池中字面量的回收为例,假如一个字符串 “abc” 已经进入了常量池中,但是当前系统没有任何一个 String 对象是叫做 “abc” 的,换句话说,就是没有任何 String 对象引用常量池中的 “abc” ,也没有其他地方引用了这个字面量,如果这时发生内存回收,而且必要的话,这个“abc”常量就会被系统清理出常量池。常量池中的其他类(接口)、方法、字段的符号引用也与此类似。
类需要同时满足下面3个条件才能算是“ 无用的类 ”:
- 该类所有的实例都已经被回收,也就是Java堆中不存在该类的任何实例。
- 加载该类的ClassLoader已经被回收。
- 该类对应的java.lang.Class 对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。
七、垃圾收集算法
标记 - 清除算法
算法分为 “标记” 和 “清除” 两个阶段:首先标记出所有需要回收的对象,在标记完成后统一回收所有被标记的对象。它的主要不足有两个:一个是效率问题,标记和清除两个过程的效率都不高;另一个是空间问题,标记清除之后会产生大量不连续的内存碎片,空间碎片太多可能会导致以后在程序运行过程中需要分配较大对象时,无法找到足够的连续内存而不得不提前触发另一次垃圾收集动作。

复制算法
将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉。这样使得每次都是对整个半区进行内存回收,内存分配时也就不用考虑内存碎片等复杂情况,只要移动堆顶指针,按顺序分配内存即可,实现简单,运行高效。缺点是将内存缩小成原来的一半,未免也太高了一点。

现在的商业虚拟机都采用复制算法来回收新生代,IBM公司的专门研究表明,新生代中的对象 98% 是 “朝生夕死”的,所有并不需要按照 1:1 的比例来划分内存空间,而是将内存分为一块较大的 Eden 空间和两个较小的 Survivor空间,每次使用 Eden 和其他一块 Survivor。当回收时,将 Eden 和 Survivor 中还存活着的对象一次性地复制到另外一块 Survivor 空间上,最后清理掉 Eden 和刚才用过的 Survivor空间。HotSpot虚拟机默认 Eden 和 Survivor 的大小比例是 8:1 ,也就是每次新生代中可用内存空间为整个新生代容量的 90% ,只有 10%的内存会被浪费。
标记 - 整理算法
首先标记出所有需要回收的对象,让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存。

未完善,待更新…
深入理解JAVA虚拟机《二》的更多相关文章
- 《深入理解Java虚拟机》虚拟机性能监控与故障处理工具
上节学习回顾 从课本章节划分,<垃圾收集器>和<内存分配策略>这两篇随笔同属一章节,主要是从理论+实验的手段来讲解JVM的内存处理机制.好让我们对JVM运行机制有一个良好的概念 ...
- 《深入理解 java虚拟机》学习笔记
java内存区域详解 以下内容参考自<深入理解 java虚拟机 JVM高级特性与最佳实践>,其中图片大多取自网络与本书,以供学习和参考.
- (1) 深入理解Java虚拟机到底是什么?
好文转载:http://blog.csdn.net/zhangjg_blog/article/details/20380971 什么是Java虚拟机 作为一个Java程序员,我们每天都在写Java ...
- 深入理解java虚拟机(7)---线程安全 & 锁优化
关于线程安全的话题,足可以使用一本书来讲解这些东西.<Java Concurrency in Practice> 就是讲解这些的,在这里 主要还是分析JVM中关于线程安全这块的内容. 1. ...
- 深入理解java虚拟机(6)---内存模型与线程 & Volatile
其实关于线程的使用,之前已经写过博客讲解过这部分的内容: http://www.cnblogs.com/deman/category/621531.html JVM里面关于多线程的部分,主要是多线程是 ...
- 深入理解java虚拟机(5)---字节码执行引擎
字节码是什么东西? 以下是百度的解释: 字节码(Byte-code)是一种包含执行程序.由一序列 op 代码/数据对组成的二进制文件.字节码是一种中间码,它比机器码更抽象. 它经常被看作是包含一个执行 ...
- 深入理解java虚拟机(4)---类加载机制
类加载的过程包括: 加载class到内存,数据校验,转换和解析,初始化,使用using和卸载unloading过程. 除了解析阶段,其他过程的顺序是固定的.解析可以放在初始化之后,目的就是为了支持动态 ...
- 深入理解java虚拟机(1)------内存区域与内存溢出
在C++领域,关于C++的内存存储,结构等等,有一本书:深度探索C++对象模型,讲解的非常透彻. 而Java确把这一工作交给了虚拟机来处理. 我们首先来看看关于内存的问题. 1.问题: 1)java ...
- 什么是HotSpot VM & 深入理解Java虚拟机
参考 http://book.2cto.com/201306/25434.html 另外,这篇文章也是从一个系列中得出的: <深入理解Java虚拟机:JVM高级特性与最佳实践(第2版)> ...
- 【Todo】深入理解Java虚拟机 读书笔记
有一个在线系列地址 <深入理解Java虚拟机:JVM高级特性与最佳实践(第2版)> http://book.2cto.com/201306/25426.html 已经下载了这本书(60多M ...
随机推荐
- c# button Command
internal class DelegateCommand : ICommand { private readonly Action _execute; private readonly Func& ...
- 关于在mysql和oracle中编码对varchar等类型的影响
今天在测试oracle的时候发现,我用varchar2(10),的字段,居然存不下"凯尔特人"四个字符:和我在学习mysql中显然是不一样的,查阅资料发现: mysql 5.0 之 ...
- VPS系统后台性能优化实战
作者: 刘用, 现任新东方APP团队高级软件工程师 2019年开始,新东方APP团队启动了长达半年以上的稳定性建设工作,为什么稳定性如此重要?因为随着每年30%以上的高速增长,现有的后端服务完全扛不住 ...
- C# - 音乐小闹钟_BetaV1.0
时间:2017-11-20 作者:byzqy 介绍: 前段时间看到别人利用Timer控件实现了检查电脑本地时间,然后对时间进行比较,最终实现闹钟功能.感觉有点意思,于是自己也做了一个小闹钟! 先看一下 ...
- EFCore 开始
1. 数据准备 新建类库项目--实体 NuGet安装: Microsoft.EntityFrameworkCore 新建类库项目--DbContext NuGet安装: Microsoft.Entit ...
- Windows系统定时备份MySQL数据库
当一个网站投入使用时,定期备份数据库是必要的事.那么,在Windows系统上,我们该如何做呢? 如下语句可以实现备份及还原MySQL数据库: 备份MySQL数据库 mysqldump -uroot - ...
- 菜鸟入门Linux之路(方法论浅谈)
Linux是为人熟知的OS之王,已"统治"世界.要想学好绝非易事. 作为菜鸟,可以与Linux亲密接触的方法很多,如视频.书籍.各种企培资料等等,如今的在线教育也如火如荼. 总结说 ...
- 20210816 你相信引力吗,marshland,party?,半夜
考场 第一眼都不可做 T1 长得就像单调栈/单调队列,推了推性质发现优弧.劣弧都合法的点对很好处理,其他情况只在一种情况合法,那么开两个单调队列分别统计距离 \(\le\frac2n,>\fra ...
- bean.xml配置数据源和读取配置文件配置数据源
一.bean.xml配置数据源 bean.xml装配bean,依赖注入其属性的时候,对应实体类中属性一定要有set方法, 二.读取配置文件配置数据源 1.配置文件 bean.xml配置: classp ...
- 部署MySQL主主复制管理器
一.概念 MMM(Master-Master replication manager for MvSQL,MySQL主主复制管理器)是一套支持双主故障切换和双主日常管理的脚本程序.MMM 使用 Per ...