最近发生了一些C#程序运行时的一些问题,发现是GC导致的问题,然后稍微研究了一下GC,因为知道Java的GC要比.NET稍微复杂一点,所以我觉得要是能弄懂Java的GC的原理,对.NET的GC的理解也能更深入一些。所以把研究到的整理做了个笔记,以免以后忘记。

什么样的对象会被GC判定要回收的对象:
     主流JVM采用可达性分析算法来判断一个对象是否需要回收。基本思想是通过称为“GC Roots”的对象作为起始点,从这些节点向下搜索,搜索走过的路径称为引用链,当一个对象不与任何引用链相连的时候,说明此对象是不可用的。
     引用计数算法也是用来判断一个对象是否应该被GC回收的一个算法。基本思想是给对象添加一个引用计数器,每当有地方引用它时,计数器加1,引用失效则减1.在任何时刻计数器为0的对象就是不可用对象。优点:实现简单,判定效率高。缺点:不能解决对象之间循环引用的问题。比如objA.instance = objB;objB.instance=objA;此时双方计数都不为0,则无法通知GC去回收他们。所以此方法并没有被主流JVM所采用。
 
可达性分析中,如何检查和处理其中包含的引用:
     首先需要了解检查过程中的问题:
  • 现在很多引用光方法区就会有数百兆,如果要逐一检查其中的引用,必然会花费大量时间。
  • 分析过程中,会出现GC停顿,如果在分析过程中引用关系不断变化,那么分析结果的准确性得不到保证,所以必须GC过程中必须要停顿所有Java执行线程,既Stop The World。
     为了解决上述问题,主流JVM采用准确式GC:采用一组称为OopMap的数据结构达到这个目的,在类加载完成、JIT编译过程中,会在特定位置记录下栈和寄存器中哪些是引用。
     但是还有一个问题,除了上述情况之外,很多指令都有可能改变引用关系,如果为每个指令都生成相应的OopMap,那会需要大量额外空间,所以JVM采用SafePoint来生成OopMap。SafePoint是按照“是否具有让程序长时间执行的特征”为标准进行选定的,明显特征是指令序列的复用,如方法调用,循环跳转,异常跳转等,除此之外,在类加载完成、JIT编译过程中记录下栈和寄存器中哪些是引用的地方也会生成SafePoint。
     对于SafePoint,如何让所有线程都跑到最近的SafePoint是一个需要考虑的问题。对于这个问题,采用的是主动式中断。中心思想是当GC需要中断线程时,不直接对线程进行操作,而是设置一个标志,每个线程执行时主动轮询这个标志,当发现中断标志为真时就在运行到SafePoint时自己中断挂起。
     有一种情况,有些线程本身就没有被分配CPU时间,如Sleep或Blocked状态,这样的线程无法轮询标志,也无法执行到SafePoint上自行中断。对于这种情况,JVM视此线程为安全区域,是指在这段代码片段中,引用关系不会发生变化,在这个区域中任意地方开始GC都是安全的。
    
 
引用的生命周期:
  • 强引用:代码中普遍存在的,类似Object obj = new Object();只要强引用还在,被引用的对象就不会被回收。
  • 软引用:有用但是非必须的引用,只有在内存将要发生内存溢出异常之前,才会被列进回收范围中,如果回收之后依     然内存不足,才会抛出内存溢出异常。
  • 弱引用:非必须对象,比软引用更弱一些,只能生存到下次GC之前,无论内存是否足够,GC工作时都会回收。
  • 虚引用:无法通过虚引用获得对象实例,唯一作用是在GC时收到系统通知。

被判定要被回收的对象,在哪些情况下可以自救(不被回收):
     当一个对象没有覆盖finalize()方法,或者finalize()已经被调用过的话,GC都会将其回收。
当不满足上述条件时,被GC判定要回收的对象会放入F-Queue的队列中,当一个对象在finalize()方法中重新和GC Roots建立连接,就可以达到自救的目的。
     注意:如果该对象在finalize()方法中实现自救,在下次被判定要被回收的时候,因为之前finalize()被调用过,所以此次回收finalize()不会被调用,故无论怎样,都会被GC回收。finalize()方法最初是为了满足C++程序员设计的方法,此方法运行代价高,不确定性大,所以在开发过程中避免使用此方法。
 
在方法区中,什么条件下会被GC回收:
  • 该类所有的实例都被回收,Java堆中不存在该类实例。
  • 加载该类的ClassLoader已经被回收。
  • 该类对应的java.lang.Class 对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。
 
堆中在被判定要回收的对象后,如何进行回收:
HotSpot采用的是分代收集算法来完成回收后的内存分配问题。基本思想是:将堆分为4部分,1个Eden空间、2个Survivor空间(From,To)和1个老年代空间。默认Eden:Survivor = 8:1.
 
 
步骤:
  1. 开始状态,对象会存在与Eden和From的空间中,在GC发生时,通过可达性分析算法判断要回收的对象,并按照回收规则进行回收,在Eden中存活的对象会放入To中,From中存活的对象的年龄加1,放入To,此时Eden和From空间是被清空的。
  2. To和From倒置,原来的To变为From,From变为To。运行一段时间后,Eden区和From区又新添加了一些对象,GC发生时,按照上述规则将Eden区存活的对象放入To中,From中存活的年龄加1放入To中。
  3. 以此反复,当From中年龄加1后到达一个阈值(年龄阈值,可以通过-XX:MaxTenuringThreshold来设置)时,将此对象放入老年代中。
  4. 当To区被填满时,无论年龄如何,都会清空To区,将其中所有的对象放入老年代中。
 
老年代中的对象通过什么方式进行回收:
     因为老年代中对象存活率高,没有额外空间进行分配担保,所以老年代使用“标记-清理”或者“标记-整理”算法进行回收。
     标记-清理:对堆中需要回收的对象进行标记,在标记完成后统一回收要回收的对象。效率不高,会产生碎片。
     标记-整理:在标记清理后,对堆进行一次压缩,让对象连续存于内存中。
 
回收采用的收集器都有哪些,各有什么特点:
 

Java GC随笔的更多相关文章

  1. java GC是何时对什么东西做什么事情

    之前学习了javaGC的原理机制,有了一定的了解,现在做一个整理总结,便于理解记忆,包括三个问题: 1. java GC是什么时候做的? 2. java GC作用的东西是什么? 3. java GC具 ...

  2. 详解Java GC的工作原理+Minor GC、FullGC

    详解Java GC的工作原理+Minor GC.FullGC 引用地址:http://www.blogjava.net/ldwblog/archive/2013/07/24/401919.html J ...

  3. Java GC回收机制

    优秀Java程序员必须了解的GC工作原理 一个优秀的Java程序员必须了解GC的工作原理.如何优化GC的性能.如何与GC进行有限的交互,因为有一些应用程序对性能要求较高,例如嵌入式系统.实时系统等,只 ...

  4. JAVA GC 简单总结

    GC分代 GC的英文全拼是Garbage Collection,意思是垃圾收集. Java 将堆内存分为三代来管理: - 年轻代 (Young Generation) - 年老代 (Old Gener ...

  5. Java GC收集器配置说明

    根据Java GC收集器具体分类,我们可以看出JVM根据需求不同提供了三种选择:串行收集器.并行收集器.并发收集器. 串行收集器只适用于小数据量的情况,我们主要了解一下并行收集器和并发收集器.默认情况 ...

  6. java gc的工作原理、如何优化GC的性能、如何和GC进行有效的交互

    java gc的工作原理.如何优化GC的性能.如何和GC进行有效的交互 一个优秀的Java 程序员必须了解GC 的工作原理.如何优化GC的性能.如何和GC进行有效的交互,因为有一些应用程序对性能要求较 ...

  7. Java GC系列(4):垃圾回收监视和分析

    本文由 ImportNew - lomoxy 翻译自 javapapers. 目录 垃圾回收介绍 垃圾回收是如何工作的? 垃圾回收的类别 垃圾回收监视和分析 在这个Java GC系列教程中,让我们学习 ...

  8. 应用JConsole学习Java GC

    应用JConsole学习Java GC 关于Java GC的知识,好多地方都讲了很多,今天我用JConsole来学习一下Java GC的原理. GC原理 在我的上一篇中介绍了Java运行时数据区,在了 ...

  9. 成为Java GC专家(3)—如何优化Java垃圾回收机制

    为什么需要优化GC 或者说的更确切一些,对于基于Java的服务,是否有必要优化GC?应该说,对于所有的基于Java的服务,并不总是需要进行GC优化,但前提是所运行的基于Java的系统,包含了如下参数或 ...

随机推荐

  1. lumen 常用辅助函数

    optional 函数接收任意参数并允许你访问对象上的属性或调用其方法.如果给定的对象为空,属性或方法调用返回 null return optional($user->address)-> ...

  2. iOS开发之--MVC 架构模式

    随着项目开发时间的增加,从刚开始那种很随意的代码风格,逐渐会改变,现在就介绍下MVC的架构模式,MVC的架构模式,从字面意思上讲,即:MVC 即 Modal View Controller(模型 视图 ...

  3. 使用async/await——Nodejs+ExpressJs+Babel

    在使用诸如restify/expressjs等Nodejs Web Framework时,我们最头疼的问题就是回调黑洞. 虽然后又Koa/Koa2号称“The Next Framework”使用co解 ...

  4. docker registry的https错误解决

    从docker1.3.2版本开始默认docker registry使用的是https,当你用docker pull 非https的docker regsitry的时候会报下面错误: Error: In ...

  5. [Ahoi2014]支线剧情[无源汇有下界最小费用可行流]

    3876: [Ahoi2014]支线剧情 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 1538  Solved: 940[Submit][Statu ...

  6. poj 1386

    Play on Words Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 11312   Accepted: 3862 De ...

  7. tortoiseSVN如何回滚(切换至)某个历史版本?

    tortoiseSVN如何回滚(切换至)某个历史版本? 1.右键需要回滚的项目,tortoiseSVN - >show log 2.右键需要回滚的历史版本,选择revert to this re ...

  8. java前后台开发之后台自动上传下载

    package downloadTest; import java.io.BufferedReader; import java.io.File; import java.io.FileInputSt ...

  9. Spoken English Practice(1、This is between you and me, Don't let it out. 2、Don't let your dreams be dreams, no matter how hard it gets, say to yourself, I'm going to make it.)

    绿色:连读:                  红色:略读:               蓝色:浊化:               橙色:弱读     下划线_为浊化 口语蜕变(2017/7/12) ...

  10. PHP 常用资源

    Apache:http://httpd.apache.org/download.cgi PHP:http://windows.php.net/download#php-5.6 MySQL:http:/ ...