GC的过程
- 哪些内存需要GC
- 判断对象是否还存活
- 引用计数法
- 给对象中添加一个引用计数器,每当一个地方引用它时,计数器值就加1;当引用失效时,计数器的值就减1,任何时候计数器为0的对象就是不可能再被使用的。
- 微软公司的COM技术,使用ActionScript3的FlashPlayer等都使用了引用计数算法来进行内存管理。
- 但是Java虚拟机里面没有选用引用计数算法来管理内存,其中最主要的原因时它很难解决对象之间相互循环引用的问题
- 可达性分析算法:
- 在主流的商用程序语言(Java, C#, Lisp等)都是通过可达性分析算法来判断对象是否存活的。
- 通过一些“GC Roots” 的对象作为起始点,从这些结点开始向下搜索,搜索所走过的路径称为引用链。当一个对象到GC Roots没有任何引用链相连时,则证明此对象时不可用的。
- Java中可作为GC Roots 的对象包括:
- 虚拟机栈(栈中的本地变量表) 中引用的对象
- 方法区中类静态属性引用的对象
- 方法区中常量引用的对象
- 本地方法栈中JNI(一般说的Native方法)引用的对象
- 在可达性分析算法中不可达的对象,仍有机会“自救”。一个对象真正被判断死亡,至少要经历两次标记过程。
- 在可达性分析算法后发现没有与GC Roots 相连接的引用链,将会第一次被标记并且进行一次筛选,条件为是否有必要执行finalize()方法。
- 如果对象没有覆盖这个方法,或者已经被虚拟机调用过了,则视为没有必要执行
- 自救:只要在finalize()方法中重新与引用链上的任何一个对象建立关联即可
- 引用计数法
- 判断对象是否还存活
2.什么时候进行GC
- 可达性分析过程中必须保证一致性,也就是指在分析过程中,对象的引用关系不能发生改变,导致GC进行时,必须停顿所有Java执行线程。
- 而当执行系统停顿下来之后,并不需要一个不漏地检查完所有执行上下文和全局的引用位置。使用一组称为OopMap的数据结构来记录哪些地方存放着对象引用。
- 在类加载完成的时候,HotSpot就把对象内什么偏移量上是什么类型的数据计算出来,在JIT编译过程中,也会在特定的位置记录下栈和寄存器中哪些位置是引用。
- 并不是什么地方都能停顿下来进行GC,只有到达安全点时才能暂停,那么如何让所有线程都到了最近的安全点再停顿下来呢?
- 抢先式中断:不需要线程的执行代码主动配合,GC发生时,首先中断全部线程,再恢复不在安全点上的线程,让它跑到安全点上。
- 主动式中断:当GC需要中断线程时,不直接对线程操作,而是仅仅简单设置一个标志,各个线程执行时,主动去轮询这个标志,发现标志为真时就主动中断挂起,而轮询标志的地方是与安全点重合的。
- 安全点机制
- 但是如果为每一条指令都生成对应的OopMap,那将会需要大量的额外空间,这样GC的空间成本将会变得很高。
- 因此设置一个安全点机制,只有在达到安全点时才能暂停。既不能太少以致于让GC等待时间太长,也不能太过于频繁以至于过分增大运行时的负荷.
- 安全区域机制
- 使用安全点机制似乎已经完美解决了如何进入GC的问题,但是这个机制能保证程序执行时,在不太长的时间内就会遇到可进入GC的安全点,但是程序不执行的时候呢
- 这个时候,就需要安全区域来解决了。安全区域是指在一段代码片段中,引用关系不会发生改变。在这个区域中的任意地方开始GC都是安全的。
- 安全点机制
3.如何进行GC
- 标记-清除算法
- 首先标记出所有需要回收的对象,在标记完成后统一回收所有被标记的对象
- 不足:
- 效率问题,标记和清除两个过程的效率都不高,
- 空间问题:标记清除之后会产生大量不连续的内存碎片,空间碎片太多可能会导致以后在程序运行过程中需要分配较大对象时,无法找到足够的连续内存而不得不提前出发另一次垃圾收集动作
- 复制算法
- 将可用内存容量划分为大小相等的两块,每次只使用其中的一块,当这一块的内存用完后,就将还存活者的对象复制到另一块上面,然后把已使用过的内存空间一次清理掉。
- 这样使得每次都是对整个半区进行内存回收,内存分配时也就不用考虑内存碎片等复杂情况,只要移动堆顶指针。按顺序分配内存即可,实现简单,运行高效。
- 问题:代价是将内存缩小为了原来的一半
- 改进:
- 目前商业虚拟机都采用这种收集算法来回收新生代,而研究表明,新生代中的对象98%是“朝生夕死”的,所以并不需要1:1的比例来划分。而是将内存分为一块较大的Eden空间和两块较小的Survivor空间。
- 当回收时,将Eden和Survivor中还存活着的对象一次性地复制到另外一块Survivor空间上,最后清理Eden和刚才用过的Survivor空间
- 这样只有10%的内存会被“浪费”
- 当然当出现Survivor空间不够用时,需要依赖其他内存(这里只老年代)进行分配担保
- 标记-整理算法
- 标记过程仍然与“标记-清除”算法一样,但后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存
- 分代收集算法
- 根据对象存活周期的不同将内存划分为几块,一般是将java堆分为新生代和老年代,这样就可以根据每个年代的特点采用最适当的收集算法。
- 在新生代中,每次垃圾收集都会有大批对象死去,只有少量存活,那就选用复制算法,只需要付出少量存活对象的复制成本就可以完成收集。
- 而老年代因为对象的存活率较高,且没有额外空间对它进行担保,就必须使用标记-清除或者标记-整理算法来进行回收
- 标记-清除算法
GC的过程的更多相关文章
- 源码分析HotSpot GC过程(二):DefNewGeneration的GC过程
由于虚拟机的分代实现,虚拟机不会考虑各个内存代如何实现垃圾回收,具体的工作(对象内存的分配也是一样)由各内存代根据垃圾回收策略自行实现. DefNewGeneration的使用复制算法进行回收.复制算 ...
- 不得不知的CLR中的GC
引言 GC 作为CLR的垃圾回收器,让程序员可以把更多的关注度放在业务上而不是垃圾回收(内存回收)上.其实很多语言也有类似的东东, 如Java也有JIT 等等 GC基本概念 垃圾回收机制的算法有好多种 ...
- 《代码的未来》读书笔记:内存管理与GC那点事儿
一.内存是有限的 近年来,我们的电脑内存都有好几个GB,也许你的电脑是4G,他的电脑是8G,公司服务器内存是32G或者64G.但是,无论内存容量有多大,总归不是无限的.实际上,随着内存容量的增加,软件 ...
- 触发Full GC执行的情况
除直接调用System.gc外,触发Full GC执行的情况有如下四种. 1. 旧生代空间不足 旧生代空间只有在新生代对象转入及创建为大对象.大数组时才会出现不足的现象,当执行Full GC后空间仍然 ...
- C#的GC机制(来自网摘复制,未整理)
第一个就是很多人用.Net写程序,会谈到托管这个概念.那么.Net所指的资源托管到底是什么意思,是相对于所有资源,还是只限于某一方面资源?很多人对此不是很了解,其实.Net所指的托管只是针对内存这一个 ...
- Android GC 那点事
版权声明:本文由陈昱全原创文章,转载请注明出处: 文章原文链接:https://www.qcloud.com/community/article/170 来源:腾云阁 https://www.qclo ...
- 如何避免后台IO高负载造成的长时间JVM GC停顿(转)
译者著:其实本文的中心意思非常简单,没有耐心的读者建议直接拉到最后看结论部分,有兴趣的读者可以详细阅读一下. 原文发表于Linkedin Engineering,作者 Zhenyun Zhuang是L ...
- GC学习笔记
GC学习笔记 这是我公司同事的GC学习笔记,写得蛮详细的,由浅入深,循序渐进,让人一看就懂,特转到这里. 一.GC特性以及各种GC的选择 1.垃圾回收器的特性 2.对垃圾回收器的选择 2.1 连续 V ...
- GC之三--GC 触发Full GC执行的情况及应对策略
1.System.gc()方法的调用 此方法的调用是建议JVM进行Full GC,虽然只是建议而非一定,但很多情况下它会触发 Full GC,从而增加Full GC的频率,也即增加了间歇性停顿的次数. ...
随机推荐
- 集合或数组转成String字符串
1.将集合转成String字符串 String s=""; for (int i = 0; i < numList.size(); i++) { if (s=="& ...
- Python全栈之路----常用模块----xml处理模块
xml是实现不同语言或程序之间进行数据交换的协议,跟json差不多,但json使用起来更简单,不过,古时候,在json还没诞生的黑暗年代,大家只能选择用xml呀,至今很多传统公司如金融行业的很多系统的 ...
- jmeter脚本录制与性能指标分析
一.浏览器代理设置(猎豹) 1.打开猎豹浏览器,进行如下图操作 2.点击局域网设置 3.输入如下信息,注意端口不要重复 4.输入网址www.baidu.com,不能正常访问就是正确的 5.查看添加的端 ...
- Introduction tp Operating System
一.虚拟化 为了让用户告诉操作系统如何利用虚拟机功能,OS提供给应用程序一些接口——系统调用,也会说提供了一个标准库. CPU通过分时达到虚拟化. 内存物理模型只是一个字节数组,读写修改需要制定地址. ...
- Nopcommerce安装,应用及二次开发视频
CSDN课程:http://edu.csdn.net/lecturer/944
- 用python给邮箱发邮件,问题,以及解决方法。
模版 import smtplib #导入相关模块 from email.mime.text import MIMEText from email.utils import formataddr de ...
- 尝试document.getElementById()失败
document.getElementById() document.getElementsByTagName() 电脑重启,新建文件后尝试成功
- H3C_IRF
1.IRF的优点: 跨设备负载均衡 规避环路 强大的网络扩展能力 带宽/可靠性增加 2.IRF域编号存在的意义: 域是一个逻辑概念,一个 IRF 对应一个 IRF 域 如果IRF 1 和IRF 2 之 ...
- LG3211 [HNOI2011]XOR和路径
题意 题目描述 给定一个无向连通图,其节点编号为 1 到 N,其边的权值为非负整数.试求出一条从 1 号节点到 N 号节点的路径,使得该路径上经过的边的权值的"XOR 和"最大.该 ...
- 2-Add Two Numbers @LeetCode
2-Add Two Numbers @LeetCode 题目 思路 题目中得到的信息有: 这是两个非负数,每位分别保存在链表的一个结点上: 逆序保存,从低位到高位依次. 一般整数的相加都是从低往高进行 ...