java中关于GC,新生代和老年代
该学习笔记是本小白查阅相关书籍借鉴大神博客自行整理而得,如有谬误,欢迎批评指正,感激不尽。
另外由于引用了不少博主的截图,所以所有截图都会标注来源,大家使用前务必表明原创作者链接,尊重原创资源。
一.关于GC
1. GC,即垃圾回收回收机制(Garbage Collection),是java中自动内存管理机制,对象内存的分配和回收全部由jvm代理完成。2. GC的优缺点:在C/C++中程序员需要手动分配和释放内存,这加重了程序员的负担,并且可能因为指针操作不当或内存泄露等原因使程序安全性无法得到保障;而在java中对象内存管理由GC代理,这大大减轻了java程序员的负担,而且避免程序员直接操作指针,堆内存得到更高效的使用;但是时间和空间不可能同时得到优化,GC机制的引入导致java程序的运行效率较C/C++低,当然不是GC这一个原因使java程序效率低下。主要是因为java中实施GC的是一个伴随线程,它会定期对对象空间进行查看标记,根据对象引用计数器是否为0判定对象的死亡而回收内存,这使程序运行增加了额外的开销,降低了效率。
二. java堆内存划分
java中堆内存的划分,看下面一张图(截图来源:https://my.oschina.net/sunnywu/blog/332870)
结合上图,java堆空间分为新生代,老年代和永久保存期,其中新生代和老年代默认比例为1:2,新生代又分为Eden,To,From(To和From称为Survivor区)三个区域,默认比例为8:1:1,这些参数可以手动调整,下面给出的表是相关参数(截图来源:http://www.blogjava.net/fancydeepin/archive/2013/09/29/jvm_heep.html):
三. GC工作原理
1. java中虚拟机的垃圾回收机制要完成功能,至少两点需要实现,即怎样确定回收对象(也就是怎么认定那些对象需要回收而另一些则不需要回收呢)以及确定回收对象后用什么算法高效回收,所以下面我们就从确定回收对象和回收算法两点浅谈GC工作原理:2. 确定回收对象:java中的对象都是通过引用(可以理解为C/C++中的指针)操作,所以jvm为每个对象维护一个引用计数器,该引用计数器描述了该对象被引用次数或是和其他对象的关联关系,如果一个对象没有被任何其他对象引用,那它就没有关联性,被判定为垃圾对象,应该被回收,因此GC确定垃圾对象是通过引用计数器完成,这和C/C++中的智能指针类似。3. 回收算法:GC回收算法经典的有三类。自从堆内存被分为不同代后,新生代和老年代其实使用不同的回收算法。
标记--清除算法(Mark--sweep)该算法很基础,它分为标记和清除两个阶段,标记阶段即标出需要回收的对象,清除阶段回收被标记对象所占内存。概算法会导致严重的内存碎片问题,可能
复制算法(Copying)为了克服内存碎片问题,该算法将内存分为两部分,它将存活对象从一块区域复制到另一块区域,然后一次清理死对象,如下图(截图 来源:
但是该算法将可用内存缩小到原来的一半,另外复制增加了额外的时间开销。标记整理算法(Mark--Compact)为了克服复制算法的缺陷,该算法将完成标记后,不是直接清理对象所占空间,而是将存活对象向一端移动然后将边界另一端内存清理回收,如下图(截图来源:http://www.cnblogs.com/dolphin0520/p/3783345.html)
划代后的垃圾回收算法
划代根据:根据广泛持久观察发现,大多对象生存时间较短,而且生存期较短的新生对象很少引用生存期较长的老年代,根据这两个特点,对内存划代管理,新生 代和老年代用不同的GC算法,可以高效管理内存。
生长原理:一般新生代被分配到eden和survivor区中(比如From区),而另一个区(比如To)清空,经过一次标记后,若对象仍然存活,则将其从survivor的现存区移动到另一个survivor区(比如To),并将其年龄设置为1,每次扫描标记过程使存活对象年龄递增,当对象年龄超过某个阈值,则将其移动到老年代(老年代的对象也有可能直接分配得到,比如一个对象需要较大内存,则直接分配到老年代)。
采用不同的GC算法:由上所述可知,新生代存活较短,老年代存活较长,所以新生代一般采用Copying算法,老年代采用更高级回收算法,比如Mark--Compact算法。