大话JVM(一):垃圾收集算法
系列介绍|本系列主要是记录学习jvm过程中觉得重要的内容,方便以后复习
在说垃圾收集算法之前,先要说一下垃圾收集,从大的讲,垃圾收集需要考虑三件事情:
1.哪些内存需要回收
2.什么时候回收
3.如何回收
JVM在执行java程序时,把他管理的内存分为多个数据区域:
1.程序计数器(记录程序执行到哪了,各线程之间独立存储, 互不影响)
2.虚拟机栈(这个栈就是我们常说的jvm的“堆”和“栈”中的栈,这里存放的是编译期间可知的各种数据类型(8种基本类型)、对象引用(reference类型,就是一种数据指针,指向对象的起始地址,或者句柄,或者是对象相关的位置)
3.本地方法栈(这个跟虚拟机栈非常相似,只不过虚拟机栈是为虚拟机执行java方法服务的,而本地方法栈是为虚拟机使用Natvie方法服务的,虚拟机规范中没有对本地方法栈做强制规定,HotSpot把虚拟机栈和本地方法栈合二为一了)
4.java堆(这堆是JVM管理内存中最多的一块,几乎所有的对象实例都存放在这里,java虚拟机规范中描述:所有对象的实例以及数据都要在堆上分配,GC就是主要管理这个区域)
5.方法区(在HotSpot中,这个区就是我们常说的“永久代”,这是一个线程共享的区域,它主要用来存储被虚拟机加载的类信息、常量、静态变量、JIT编译后的代码等数据)
其中程序计数器、虚拟机栈、本地方法栈3个区随线程而生,随线程而灭;栈中的栈帧随方法的进入和退出有条不紊的执行出栈和入栈操作,内存的分配是在类结构确定下来时就已知的,内存的分配和回收都具有确定性,因此这几个区域不需要过多考虑回收问题,因为方法结束或线程结束时,内存自然跟着回收了。主要考虑的是JAVA堆和方法区,因为这部分内存分配是动态的,程序在运行时才知道创建哪个对象实例,执行哪个方法。
GC回收前需要考虑对象已经“死”了吗
判断对象是否存活有两种算法,一种是引用计数算法,另一种是可达性算法
1)引用计数算法
引用计数算法就是给对象中添加一个引用计数器,每当有地方引用他时,计算器值加1,当引用失效时,计数器值减1,计算器值为0时,表示对象不再被使用。
引用计数算法实现简单,判定效率高,但是有个致命确定,就是循环引用时无法正常工作。
public class CountGC {
public Object instance = null;
public static void testGC(String[] args){
//创建了一个CountGC对象,并发把它赋给了countGC1,CountGC的对象引用计数值加1
CountGC countGC1 = new CountGC();
//又创建了一个CountGC对象,并发把它赋给了countGC2,另一个CountGC的对象引用计数值加1
CountGC countGC2 = new CountGC();
//把第一个CountGC对象的instance字段赋值上第二个CountGC对象,第二个CountGC对象引用计数值再加1,这是就变成了2
countGC1.instance = countGC2;
//把第二个CountGC对象的instance字段赋值上第一个CountGC对象,第一个CountGC对象的引用计数值再加2,这时也变成了2
countGC2.instance = countGC1;
//countGC1赋空值,第一个CountGC对象引用减1
countGC1 = null;
//countGC2赋空值,第二个CountGC对象引用减1
countGC2 = null;
//如果这时候回收,这两个CountGC对象是无法回收的,因为他们的引用计数值不为0
System.gc();
}
}
2)可达性算法
可达性算法就是以一个 GC Roots对象向下搜索,能搜索到的对象就说明是存活的,搜索不到的对象说明就是不可用的。

不管是引用计数算法,还是不可达算法,最终判断对象是否存活的关键,是引用。
下面我们正式介绍垃圾收集算法,我们主要介绍下面几种算法:
1.标记 - 清除算法
2.复制算法
3.标记 - 整理算法
4.分代收集算法
1)标记 - 清除算法
标记 - 清除算法就跟他的名字一样,分为“标记”和“清除”两阶段,首选标记出所有可回收的对象,然后统一回收所有被标记的对象。
标记 - 清除算法是最基础的算法,后续的几个算法都是基于这种算法思路对其不足进行改进得到的。
它的不足主要表现在两个方面,一是效率问题,二是空间利用问题
效率不高是因为,它标记是需要遍历所有内存空间,清除时也是一个个清除
空间利用率问题是因为清理后内存空间是零碎的,当需要分配大空间时,没有连续空间,需要再次触发GC
回收前状态:
回收后状态:

2)复制算法
为了解决效率问题,复制算法出现了,它将可用内存按容量划分为大小相等的两块,每次只使用其中一块,当这一块的内存用完时,就将存活的对象复制到另外一块内存上面,然后把使用过的内存空间一次清理掉。
回收前状态:
回收后状态:

复制算法的优点是:实现简单,运行高效
缺点是:浪费内存,从上面算法来看,实际使用只有原来内存的一半,浪费太大了。
现在的商用虚拟机都采用这种算法来回收新生代,IBM公司专门研究表明,新生代中的对象98%都是“朝生夕死”的,所以并不需要按照1:1来划分内存,而是将内存分成一块较大的Eden空间和两块较小的Survivor空间,每次使用Eden和一块Survivor,另一个Survivor作为预留空间。(HotSopt中默认分配比例是8:1:1,这样只浪费了10%的空间)。
采用这种内存分配方式的回收过程:
1.每次使用Eden和一块Survivor,另一块Survivor作为预留空间,
2.标记出Eden和一块Survivor空间中存活的对象,并复制到另一块Survivor空间中
3.清理掉使用过的Eden和一块Survivor空间。
这种做法有一个不足之处,就是当Eden和一块Survivor空间中存活的对象(对象存活率较高)大于另一块Survivor空间时,需要老年代担保分配,这时候效率非常低(因为存活对象是一个个复制到预留内存空间的,对象存活率特别高时,对象数也会非常多),而且还浪费空间(这时候预留空间就起不到作用了,浪费了预留空间的内存)。
因为当发现Eden和一块Survivor空间中存活的对象大于另一块Survivor空间时,这时候会把存活对象直接分配到老年代。
3)标记 - 整理算法
标记 - 整理算法就是把标记 - 清除算法中的清除替换成整理,整理时不直接对回收对象清理,而是让所有存活对象向一端移动,然后直接清理掉边界以外的内存。
回收前状态:
回收后状态:

这个算法是根据老年代的特点设计出来的,因为老年代中对象存活率较高,并且没有额外的空间对它进行分配担保,就必须采用“标记 - 清楚” 或者 “标记 - 整理”算法来进行回收。
4)分代收集
当前商业虚拟机都是采用“分代收集”算法,这种算法并没有什么新的思想,只是按照对象存活周期不同将内存划分为几个区域,就像java堆中的新生代和老年代一样,这样做的好处是,可以根据各个年代的特点采用适当的收集算法。
大话JVM(一):垃圾收集算法的更多相关文章
- JVM中垃圾收集算法总结
通过前面的介绍我们了解了对象创建和销毁的过程.那么JVM中垃圾收集器具体对对象回收采用的是什么算法呢?本文主要记录下JVM中垃圾收集的几种算法. JVM的垃圾回收的算法 标记-清除算法(Mark- ...
- 深入浅出JVM之垃圾收集算法
判断哪些对象需要被回收 引用计数算法: 给对象中添加一个引用计数器,每当有一个地方引用时,计数器值就加1:当引用失效时,计数器值就减1:任何时刻计数器为0的对象就是不可能再被使用的. 但是JVM没有使 ...
- JVM笔记-垃圾收集算法与垃圾收集器
1. 一些概念 1.1 垃圾&垃圾收集 垃圾:在 JVM 语境下,"垃圾"指的是死亡的对象所占据的堆空间. 垃圾收集:所谓"垃圾收集",就是将已分配出去 ...
- 深入理解JVM(二)--垃圾收集算法
一. 概述 说起垃圾收集(Garbage Collection, GC), 大部分人都把这项技术当做Java语言的伴随生产物. 事实上, GC的历史远远比Java久远, 1960年 诞生于MIT的Li ...
- 面试刷题25:jvm的垃圾收集算法?
垃圾收集是java语言的亮点,大大提高了开发人员的效率. 垃圾收集即GC,当内存不足的时候触发,不同的jvm版本算法和机制都有差别. 我是李福春,我在准备面试,今天的问题是: jvm的垃圾回收算法有哪 ...
- JVM垃圾收集算法之标记算法
前言 总所周知,jvm的垃圾收集算法一般包括标记.清除.整理三个阶段,最近在看了有关于垃圾收集的标记算法,记录一下自己的理解. 垃圾收集中标记算法有两种:一种是引用计数法,一种是根搜索算法. 引用记数 ...
- 深入理解Java虚拟机 - 垃圾收集算法与垃圾收集器
1. 垃圾收集算法 JVM的垃圾收集算法在不同的JVM实现中有所不同,且在平时工作中一般不会深入到收集算法,因此只对算法做较为简单的介绍. 1.1 标记-清除算法 ...
- JVM垃圾收集算法(标记-清除、复制、标记-整理)
[JVM垃圾收集算法] 1)标记-清除算法: 标记阶段:先通过根节点,标记所有从根节点开始的对象,未被标记的为垃圾对象(错了吧?) 清除阶段:清除所有未被标记的对象 2)复制算法: 将原有的内存空间 ...
- JVM垃圾收集算法
JVM垃圾收集 1. 判断对象是否存活 引用计数算法 对象添加一个引用计数器,每个地方引用它,计数器值加+1:当引用失效,计算器值减1:任何时刻计数器为0的对象不可能被使用.引用计数算法实现简单,高效 ...
随机推荐
- R语言和RStudio的一些用法,常用命令等
控制台: Up/down 回忆之前的命令 Ctrl+Up 回顾命令列表(可先输入前缀进行查找) 焦点: ctrl+ 移动焦点到source编辑器 ctrl+ 移动焦点到console ctrl+L 清 ...
- CRT和EXCRT简单学习笔记
中国剩余定理CRT 中国剩余定理是要求我们解决这样的一类问题: \[\begin{cases}x\equiv a_1\pmod {b_1} \\x\equiv a_2 \pmod{b_2}\\...\ ...
- TCP BBR - 如何安装、启动、停止BBR!
TCP BBR从Linux 4.9 内核开始,就作为它内核的一部分存在了,如果想使用BBR,那么首先就是判断内核版本是否大于4.9,如果符合版本标准,那么直接启动BBR就可以了,如果低于4.9,升级内 ...
- Mac OS 10.12 - 如何能够像在Windows一样切换中英文输入法和大小写键?
最开始,我切换中英文输入法和大小写键是按照下面博客做到的: http://www.cnblogs.com/sunylat/p/6415563.html 但是当我安装完毕搜狗输入法后,切换中英文输入法和 ...
- 920. Number of Music Playlists
Your music player contains N different songs and she wants to listen to L (not necessarily different ...
- 898. Bitwise ORs of Subarrays
We have an array A of non-negative integers. For every (contiguous) subarray B = [A[i], A[i+1], ..., ...
- Python小白学习之路(八)—【变量】【基本数据类型分类】【集合】【集合的功能】
一.变量 变量的作用:记录状态的变化变量的值:描述不同的状态 二.五大基本数据类型的分类 五大基本数据类型(数字 字符串 列表 元祖 字典) 按照可变不可变来进行分类 可变:列表.字典 不可变:字符串 ...
- 使用ie的filter来解决rgba在IE8下没有效果的问题
使用ie的filter来解决rgba在IE8下没有效果的问题,css代码如下: background: rgba(255,255,255,0.1); filter:progid:DXImageTran ...
- Swift的Guard语句
与if语句相同的是,guard也是基于一个表达式的布尔值去判断一段代码是否该被执行.与if语句不同的是,guard只有在条件不满足的时候才会执行这段代码.你可以把guard近似的看做是Assert,但 ...
- apache2.4配置weblogic12c集群(linux环境)
首先确定环境已装apache2.4,没装的话可以看下这篇文章apache2.4一键脚本安装(linux环境) 1.下载apache分发模块mod_wl_24.so 下载apache2.4的weblog ...