Java GC

作者: yoga0108 | 来源:发表于2017-03-08 21:55 被阅读0次

    摘要

    总结了下jvm 的通用的gc算法以及概念。主要记录思路为

    1. 问题定义
    2. 回收哪些对象
    3. 如何回收
    4. 相关阅读
    5. 自带问题

    GC具体如何回收,回收机制最后落实成什么样,跟jvm内部实现也有很大关系,比如jdk1.8 与1.7的回收机制就已经有不同了。具体实现需要对版本具体研究,此处之只记录下通用的一些概念。

    问题定义

    GC即垃圾回收,jvm提供自动回收内存垃圾机制。自动回收内存中无用的对象,释放其占用的资源,以给后续使用。

    回收哪些对象

    首先,从哪里回收,从jvm 内存模型来看,线程私有的内存区域(java方法栈、native方法栈、程序计数器)生命周期随线程生灭,不存在回收问题。所以jvm回收的内存区域目标为(堆,方法区)。
    其次,哪些对象是无用的对象。对于jvm来说,没有被你的程序使用的对象即为无用对象。

    如何回收

    如何从内存中回收对象,这个问题可以分成两部走:找出无用对象,回收无用对象占用的空间以便后续使用

    找出无用对象

    这里通常会讨论两种算法:引用计数法,GC Root(拓扑算法)。

    如何回收

    回收无用对象也可分为两步:回收对象占用的空间,清理剩余空间。
    一般常用的回收算法有:

    1.标记-清除:将标记的无用对象占用空间清空,这样回收会比较快,缺点是回收完的可用内存是零散分布的,不方便后续使用。
    2.复制算法:可用内存空间分成两份,每次只用其中一份,回收时,将当前存活的对象复制到另一份空间中,当前空间完全清空,这样能保证内存中空间一定是连续的,方便后续内存分配。缺点为使用中每次只能使用一般的空间,浪费内存,适用于少量内存存活的场景。
    3.标记-整理:即在标记-清除的基础上,整理清理后打散的内存空间为连续分布。这个算法使用于大量内存存活的场景。
    4.分代整理:其实就是之前三种算法的结合使用。

    这里对JVM 使用分代整理算法 使用理解很有帮助的一点是:
    研究发现,jvm的对象大多存活事件很短,也就是书上所说的“朝生夕死”。

    试想,jvm 1min内创建了100m的对象,但是每次gc后只留了10m的存活对象,这种情况下选复制算法比较划算。
    但是其实gc完成后只有1/10的对象存活,则用来做复制的备份内存并不需要1/2,也只需要1/10即可。
    以上这就是jvm 常说的“新生代”,新生代分为(eden, survivor),其中所有新建的对象都在eden区,surviror即为复制算法的两个备份区(s0, s1),默认eden:s0:s1=8:1:1,基本这个配比思想为java 新创建的对象能存活下来的比例1/10 。只需要分1/10的空间来存储gc后存活的对象。

    Paste_Image.png

    survivor的设计初衷为保留“朝令夕死”的少量短命对象,所以suvivor必然是一块很小的区域。当内存中存活的对象越来越多时候,根据“存活的越久的对象就越有可能继续存活”这种思想,把存活期超过一定阀值的对象从survivior区中搬出,移到"老年代"中,即老年代用来保存存活期较久的对象。老年代的设计初衷为保存大量可能继续存活的对象。这种区域标记-整理算法比较适合,所以老年代一般使用标记-整理。

    新生代+老年代,基本就是jvm的堆内存划分了。

    方法区回收,则主要回收类对象、常量。

    相关阅读

    1.http://www.oracle.com/webfolder/technetwork/tutorials/obe/java/gc01/index.html
    2.《深入理解Java虚拟机》
    3.http://www.cnblogs.com/redcreen/archive/2011/05/04/2037056.html

    自带问题

    在oom试验中,设置了perSize=10m maxPerSize=10m ,通过string.intern循环产生string常量,却一直没有perm gen oom.查看jmap -heap ,发现内存中ps old gen 已经600M+, per gen 2m+.为什么?

    相关文章

      网友评论

          本文标题:Java GC

          本文链接:https://www.haomeiwen.com/subject/zoevgttx.html