JVM学习二:垃圾收集(Garbage Collection,GC)机制
JVM的GC分为两个主要部分,第一部分是判断对象是否已死(堆内存的垃圾回收占主要部分,方法区(metaspace)的内存回收在最新的官方文档中未给出详细解释,暂时不做讨论范围),第二部分是对内存区进行回收用于下次的内存分配。
一、判断对象是否已死
JDK 8的VM实现是Hotspot虚拟机,它采用的是可达性分析算法。
a.引用计数算法
给每个对象添加一个引用计数器,每当有一个地方引用它时,计数器值就加1;当引用失效时计数器的值就减1。但在VM中它无法解决的一个问题就是循环引用问题(也是 Hotspot没有采用它的主要原因):
public class ReferenceCountingGC {
public Object instance = null;
private static final int _1MB = 1024 * 1024;
private byte[] size = new byte[_1MB]; //这个成员属性的意义在于占据堆内存,以便稍后观察JVM是否回收了了堆内存
public static void main(String[] args) {
ReferenceCountingGC obj1 = new ReferenceCountingGC(),obj2 = new ReferenceCountingGC();
obj1.instance = obj2;
obj2.instance = obj1; //这两行代码为循环引用的发生场景
obj1 = null;
obj2 = null; //这两行代码导致对象无法访问,但是他们对应的计数器值并不为0,如果采用的是引用计数算法,将不会发生堆内存回收
System.gc(); //垃圾回收发生在此行,分为新生代垃圾回收、堆内存和元空间的回收
} }

b.可达性分析算法
这个算法的基本思路就是通过一系列成为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链,当一个对象到GC Roots没有任何引用链的时,则证明此对象是不可用的,即对象已死。

Object5、Object6、Object7到GC Roots没有引用链的存在,因此这三个对象会回收。
在Java语言中,可作为GC Roots的对象包括下面几种:
虚拟机栈(栈中的本地变量表)中引用的对象
本地方法栈中JNT(即一般说的Native方法)引用的对象
方法区中常量引用的对象
方法区中变量引用的对象
c.再谈引用
判断一个对象是否已死,无论是引用计数算法还是可达性分析算法,它们都与引用有关,在JDK1.2以后,Java中的引用分为Strong Reference(强引用)、Soft Reference(软引用)、弱引用(Weak Reference)、虚引用(Phantom Reference):
强引用就是指在程序代码中普遍存在的,类似“Object obj = new Object()”这类的引用,只要引用还存在,垃圾收集器永远不会回收掉被引用的对象。
软引用是用来描述还有用但非必需的对象。对于软引用关联的对象,在系统将要发生内存溢出之前,将会把这些对象列进回收范围进行二次回收,如果这次回收还没有足够的内存,才会抛出内存溢出异常。在JDK1.2之后,提供了SoftReference类来实现软引用。
弱引用也是来描述非必需对象的,但是它的强度比软引用更弱一些,被弱引用关联的对象只能生存到下一次内存回收之前。在JDK1.2后,提供了WeakReference类来实现弱引用。
虚引用的存在不会对被引用对象产生任何影响,为一个对象设置虚引用的目的就是能在这个对象被垃圾收集器回收时收到一个系统的通知。
二、内存回收算法
a.标记-清除算法
b.复制算法
c.标记-整理算法
d.分代收集算法
现代的商业虚拟机都使用分代收集算法,即堆内存中的新生代采用复制算法,老年代采用标记-清除或者标记-整理算法。
注:新生代和老年代的意义是相对于GC的而不是运行时数据区,不同GC对于堆内存的划分有所不同,垃圾回收的侧重点也不相同。
The blue area in Figure 3-1, "Typical Distribution for Lifetimes of Objects" is a typical distribution for the lifetimes of objects. The x-axis is object lifetimes measured in bytes allocated. The byte count on the y-axis is the total bytes in objects with the corresponding lifetime. The sharp peak at the left represents objects that can be reclaimed (in other words, have "died") shortly after being allocated. Iterator objects, for example, are often alive for the duration of a single loop.
Figure 3-1 Typical Distribution for Lifetimes of Objects

To optimize for this scenario, memory is managed in generations (memory pools holding objects of different ages). Garbage collection occurs in each generation when the generation fills up. The vast majority of objects are allocated in a pool dedicated to young objects (the young generation), and most objects die there. When the young generation fills up, it causes a minor collection in which only the young generation is collected; garbage in other generations is not reclaimed. Minor collections can be optimized, assuming that the weak generational hypothesis holds and most objects in the young generation are garbage and can be reclaimed. The costs of such collections are, to the first order, proportional to the number of live objects being collected; a young generation full of dead objects is collected very quickly. Typically, some fraction of the surviving objects from the young generation are moved to the tenured generation during each minor collection. Eventually, the tenured generation will fill up and must be collected, resulting in a major collection, in which the entire heap is collected. Major collections usually last much longer than minor collections because a significantly larger number of objects are involved.
Figure 3-2, "Default Arrangement of Generations, Except for Parallel Collector and G1" shows the default arrangement of generations (for all collectors with the exception of the parallel collector and G1):
Figure 3-2 Default Arrangement of Generations, Except for Parallel Collector and G1
At initialization, a maximum address space is virtually reserved but not allocated to physical memory unless it is needed. The complete address space reserved for object memory can be divided into the young and tenured generations.
The young generation consists of eden and two survivor spaces. Most objects are initially allocated in eden. One survivor space is empty at any time, and serves as the destination of any live objects in eden; the other survivor space is the destination during the next copying collection. Objects are copied between survivor spaces in this way until they are old enough to be tenured (copied to the tenured generation).
新生代中的对象在下面情况中进入老年代:
大对象通过分配担保直接进入老年代(大对象大小的临界值根据不同GC而设定)
长期存活的对象
大对象直接进入老年代
Minor GC后,Survivor仍然放不下
动态年龄判断 ,大于等于某个年龄的对象超过了survivor空间一半 ,大于等于某个年龄的对象直接进入老年代
JVM学习二:垃圾收集(Garbage Collection,GC)机制的更多相关文章
- JVM总括二-垃圾回收:GC Roots、回收算法、回收器
JVM总括二-垃圾回收:GC Roots.回收算法.回收器 目录:JVM总括:目录 一.判断对象是否存活 为了判断对象是否存活引入GC Roots,如果一个对象与GC Roots没有直接或间接的引用关 ...
- JVM学习二:JVM之GC算法和种类
我们前面说到了JVM的常用的配置参数,其中就涉及了GC相关的知识,趁热打铁,我们今天就学习下GC的算法有哪些,种类又有哪些,让我们进一步的认识GC这个神奇的东西,帮助我们解决了C 一直挺头疼的内存回收 ...
- JVM笔记(二) 垃圾收集器(1)
垃圾收集器 主要通过阅读<深入了解Java虚拟机>(周志明 著)和网络资源汇集而成,为本人学习JVM的笔记.同时,本文理论基于JDK 1.7版本,暂不考虑 1.8和1.9 的新特性,但可能 ...
- hive impala C++ Java垃圾回收 Garbage Collection GC
hive impala impala 推荐每个节点内存 2^7~2^8GB Impala与Hive的比较 - 文章 - 伯乐在线 http://blog.jobbole.com/43233/ &l ...
- JVM学习笔记:虚拟机的类加载机制
JVM类加载机制分两部分来总结: (1)类加载过程 (2)类加载器 一.JVM类加载过程 类的加载过程:加载 →连接(验证 → 准备 → 解析)→ 初始化. 类的生命周期:加载 →连接(验证 → 准备 ...
- python 之gc(回收机制)--garbage collection(GC垃圾回收)
######################引用计数######################### 引用计数:python 当中一种用来解决垃圾回收的策略之一 char 1个字节(2**8) in ...
- jvm系列 (二) ---垃圾收集器与内存分配策略
垃圾收集器与内存分配策略 前言:本文基于<深入java虚拟机>再加上个人的理解以及其他相关资料,对内容进行整理浓缩总结.本文中的图来自网络,感谢图的作者.如果有不正确的地方,欢迎指出. 目 ...
- JVM学习记录-垃圾收集器
先回顾一下上一篇介绍的JVM中常见几种垃圾收集算法: 标记-清除算法(Mark-Sweep). 复制算法(Copying). 标记整理算法(Mark-Compact). 分代收集算法(Generati ...
- JVM学习(二):垃圾回收
我刚工作的时候问一个前辈,我们能针对JVM做出什么样的优化.前辈说,我们系统现在的性能并不需要调优,用默认的配置就能满足现在的需求了.我又问,那你为什么要看JVM相关的书呢?前辈微微一笑,悠悠地来了句 ...
随机推荐
- vue-文字块收缩与展开功能
在设计图中要求的效果为: 文字限制超过9行即隐藏,并显示“展开”按钮,点击按钮进行切换,控制文本全部展示和部分展示 在原本的实现过程中,使用了红框内的判断方式: 页面代码: 样式则规定嵌套元素给一个死 ...
- 博客编辑器Open Live Writer的安装以及配置
下载安装包 访问官网 http://openlivewriter.org/ 或者微软商店 https://www.microsoft.com/en-us/p/open-live-writer/9n ...
- css 积累
1.input 初始化 input { -webkit-tap-highlight-color: rgba(0,0,0,0); border: none; } input:focus { outlin ...
- 版本管理工具Git(2)git的使用
上一篇带大家认识了Git,在本篇中将讲解Git的安装及使用: Git系列导航 版本管理工具Git(1)带你认识git 版本管理工具Git(2)git的安装及使用 版本管理工具Git(3)VS下如何使用 ...
- Angular2+URL中的 # 引发的思考
1.先分析 # 的作用 1.1. # 的涵义 #代表网页中的位置.其右面的字符就是该位置的标识符.比如,http://www.example.com/index.html#print就代表网页inde ...
- 利用Delphi编写Socket通信程序
一.Delphi与Socket 计算机网络是由一系列网络通信协议组成的,其中的核心协议是传输层的TCP/IP和UDP协议.TCP是面向连接的,通信双方保持一条通路,好比目前的电话线,使用telnet登 ...
- 【转载】安装 gephi 软件
作者:小小爽链接:https://www.zhihu.com/question/21268129/answer/354924066来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注 ...
- 搭建本地yum源
本地yum源其实非常容易搭建 首先进入/etc/yum.repos.d/ 将原来的yum源备份后移除,然后新建dvd.repo: 内容如下: [base] name=base baseurl=file ...
- X-template
<body> <div id="app"> <hello-world></hello-world> </div> < ...
- 【转载】IL指令集
转载自:http://www.cnblogs.com/knowledgesea/p/5461040.html 名称 说明 Add 将两个值相加并将结果推送到计算堆栈上. Add.Ovf 将两个整数相加 ...