最近发生了一些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. React + Redux 入门(一):抛开 React 学 Redux

    http://www.hacke2.cn/think-in-react-redux-1/

  2. DecimalFormat 四舍五入Float类型的坑

    今天又踩了一个坑,使用DecimalFormat来完毕四舍五入.可是传入的是float类型,几轮測试才发现一个问题,传入的float会被转为double类型.大家都知道float是4位,double是 ...

  3. iOS开发之 -- 判断是否第一次登陆APP

    判断是否第一次登陆app,具体方法如下: if (![[NSUserDefaults standardUserDefaults]boolForKey:@"firstLaunch"] ...

  4. iOS开发之--svn工具Cornerstone上传忽略.a文件的处理方法

    工程文件上传到svn中,.a文件会自动屏蔽(应该叫屏蔽,反正就是上传不上去) 用Cornerstone工具,解决这个问题 1.打开Cornerstone左上角,点Cornerstone->Pre ...

  5. Qt slot中获取sender

    调用sender();函数 例如获取一个QRadioButton QRadioButton *rb = qobject_cast<QRadioButton *>(sender());

  6. 内存泄露,GC相关

    内存泄露就是对象不在GC的掌控之内 下面对象会发生内存泄露现象: 1.没有引用的对象 2.虚,软,弱 引用对象 GC引用的对象指的是 1.JavaStack中引用的对象 2.方法区中静态引用指向的对象 ...

  7. uva 110 Meta-Loopless Sorts 用程序写程序 有点复杂的回溯水题

    题目要求写一个直接用比较排序的pascal程序,挺有趣的一题. 我看题目数据范围就到8,本来以为贪个小便宜,用switch输出. 然后发现比较次数是阶乘级别的,8的阶乘也是挺大的,恐怕会交不上去. 于 ...

  8. 【BZOJ2253】[2010 Beijing wc]纸箱堆叠 cdq分治

    [BZOJ2253][2010 Beijing wc]纸箱堆叠 Description P 工厂是一个生产纸箱的工厂.纸箱生产线在人工输入三个参数 n p a , , 之后,即可自动化生产三边边长为 ...

  9. 160617、使用espeak将文字转语音(TTS)

    http://www.eguidedog.net/cn/WebSpeech_cn.php 简单使用例子: <html> <head> <meta http-equiv=& ...

  10. IDEA安装Python环境,并加入Anaconda环境

    为什么做这个事情? 1.首先,Anaconda中已经有各种科学计算环境,包括后面安装的tensorflow 2.通过IDEA中配置就达到了Scala.Python.Java同时运行的目的. Intel ...