1. 哪些内存需要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的过程的更多相关文章

  1. 源码分析HotSpot GC过程(二):DefNewGeneration的GC过程

    由于虚拟机的分代实现,虚拟机不会考虑各个内存代如何实现垃圾回收,具体的工作(对象内存的分配也是一样)由各内存代根据垃圾回收策略自行实现. DefNewGeneration的使用复制算法进行回收.复制算 ...

  2. 不得不知的CLR中的GC

    引言 GC 作为CLR的垃圾回收器,让程序员可以把更多的关注度放在业务上而不是垃圾回收(内存回收)上.其实很多语言也有类似的东东, 如Java也有JIT 等等 GC基本概念 垃圾回收机制的算法有好多种 ...

  3. 《代码的未来》读书笔记:内存管理与GC那点事儿

    一.内存是有限的 近年来,我们的电脑内存都有好几个GB,也许你的电脑是4G,他的电脑是8G,公司服务器内存是32G或者64G.但是,无论内存容量有多大,总归不是无限的.实际上,随着内存容量的增加,软件 ...

  4. 触发Full GC执行的情况

    除直接调用System.gc外,触发Full GC执行的情况有如下四种. 1. 旧生代空间不足 旧生代空间只有在新生代对象转入及创建为大对象.大数组时才会出现不足的现象,当执行Full GC后空间仍然 ...

  5. C#的GC机制(来自网摘复制,未整理)

    第一个就是很多人用.Net写程序,会谈到托管这个概念.那么.Net所指的资源托管到底是什么意思,是相对于所有资源,还是只限于某一方面资源?很多人对此不是很了解,其实.Net所指的托管只是针对内存这一个 ...

  6. Android GC 那点事

    版权声明:本文由陈昱全原创文章,转载请注明出处: 文章原文链接:https://www.qcloud.com/community/article/170 来源:腾云阁 https://www.qclo ...

  7. 如何避免后台IO高负载造成的长时间JVM GC停顿(转)

    译者著:其实本文的中心意思非常简单,没有耐心的读者建议直接拉到最后看结论部分,有兴趣的读者可以详细阅读一下. 原文发表于Linkedin Engineering,作者 Zhenyun Zhuang是L ...

  8. GC学习笔记

    GC学习笔记 这是我公司同事的GC学习笔记,写得蛮详细的,由浅入深,循序渐进,让人一看就懂,特转到这里. 一.GC特性以及各种GC的选择 1.垃圾回收器的特性 2.对垃圾回收器的选择 2.1 连续 V ...

  9. GC之三--GC 触发Full GC执行的情况及应对策略

    1.System.gc()方法的调用 此方法的调用是建议JVM进行Full GC,虽然只是建议而非一定,但很多情况下它会触发 Full GC,从而增加Full GC的频率,也即增加了间歇性停顿的次数. ...

随机推荐

  1. s21day16 python笔记

    s21day16 python笔记 一.模块 1.1 模块的定义 模块的定义 可以吧一个py文件或一个文件夹(包)当作一个模块,以便于以后其他py文件的调用 包的定义(python2与python3的 ...

  2. git 恢复本地误删文件

    git status git reset HEAD 路径(git status 会显示的路径) git checkout 路径

  3. 使用getInstance()方法的原因及作用

    使用getInstance()方法的原因及作用 先举例说明: 下面是一个例子,为什么要把这个类实例化?有什么好处? //实例化 public static DBConnect instance; pu ...

  4. Git创建本地仓库、与远程仓库关联

    不知道对不对,不过我这么干能用了嘿嘿 下载好git以及配置密钥什么的就不说了,网上一p眼子 在本地找个变成仓库的文件夹,打开git命令行工具cd到这个目录,然后git init创建本地仓库 然后上gi ...

  5. FFT算法详解

    啊…本来觉得这是个比较良心的算法没想到这么抽搐这个算法真是将一个人的自学能力锻炼到了极致qwqqwqqwq 好的,那我们就开始我们的飞飞兔FFTFFTFFT算法吧! 偷偷说一句,FFTFFTFFT的代 ...

  6. Postman 使用方法详解

    转自:https://blog.csdn.net/fxbin123/article/details/80428216 一.Postman背景介绍 用户在开发或者调试网络程序或者是网页B/S模式的程序的 ...

  7. Linux第六节课学习笔记

    if条件测试语句可以让脚本根据实际情况自动执行相应的命令,可以分为单分支.双分支与多分支. /dev/null为无回收功能的垃圾箱. read是用来读取用户输入信息的命令,-p用来显示提示信息. fo ...

  8. sed命令讲解

    sed命令选项及作用 -n 不打印所有的行到标准输出 -e 表示将下一个字符串解析为sed编辑命令 -f 表示正在调用sed脚本文件 sed编辑命令 p 打印匹配行 = 打印文件行号 a\ 在定位行号 ...

  9. c# 枚举安卓系统中所有目录及文件名

    using Android.App; using Android.Widget; using Android.OS; using System.Runtime.InteropServices; nam ...

  10. HBASE 基础命令总结

    HBASE基础命令总结 一,概述 本文中介绍了hbase的基础命令,作者既有记录总结hbase基础命令的目的还有本着分享的精神,和广大读者一起进步.本文的hbase版本是:HBase 1.2.0-cd ...