最近发生了一些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. Python爬虫(七)

    源码: import requests import re from my_mysql import MysqlConnect # 获取详情页链接和电影名称 def get_urls(page): u ...

  2. js实现jquery的offset()

    用过jQuery的offset()的同学都知道 offset().top或offset().left很方便地取得元素相对于整个页面的偏移. 而在js里,没有这样直接的方法,节点的属性offsetTop ...

  3. nyoj1237 最大岛屿(河南省第八届acm程序设计大赛)

    题目1237 pid=1237" style="color:rgb(55,119,188)">题目信息 执行结果 本题排行 讨论区 最大岛屿 时间限制:1000 m ...

  4. 状态栏,ActionBar,工具栏高度调整

    1.在属性中可以这样设置更改ActionBar的高度android:layout_marginTop="?android:attr/actionBarSize" Rect fram ...

  5. 【BZOJ4254】Aerial Tramway 树形DP

    [BZOJ4254]Aerial Tramway 题意:给你一座山上n点的坐标,让你在山里建m条缆车,要求缆车两端的高度必须相等,且中间经过的点的高度都小于缆车的高度.并且不能存在一个点位于至少k条缆 ...

  6. 使用pinyin4j实现汉字转拼音

    1. maven项目,请在pom.xml里边添加包依赖相关配置: <dependency> <groupId>net.sourceforge.pinyin4j</grou ...

  7. iOS 内存管理(转载)

     N久没维护这个博客了,从开始接触编程到现在已经三四年了.不太习惯写博客,这应该是个不好的习惯.所以从哪哪天开始,我得改变自己 (:       . 文采不太好,因此很多的文章都会借鉴他人的,但是我一 ...

  8. px、dp、sp、mm、in、pt这些单位有什么区别?

    相信每个Android新手都会遇到这个问题,希望这篇帖子能让你不再纠结. px: 即像素,1px代表屏幕上一个物理的像素点: px单位不被建议使用,因为同样100px的图片,在不同手机上显示的实际大小 ...

  9. 100个常用的linux命令(转)

    原文:http://blogread.cn/it/article/6368?f=wb 1,echo “aa” > test.txt 和 echo “bb” >> test.txt / ...

  10. BS一机双屏的解决方式

    一.WebSocket通讯 WebSocket protocol 是HTML5一种新的协议.它实现了浏览器与server全双工通信. 为保证socket不间断.使用下面类库进行socket通讯. ht ...