• 深入理解Java虚拟机03--垃圾收集器与内存分配策略


    一.概述 

    • 哪些内存需要回收?
    • 什么时候回收?
    • 如何回收?

    二.对象已死吗 

    1.引用计数算法 

    1. 定义:给对象添加一个引用计数器,当增加一个引用时,加1,当一个引用时,减1;

    2. 缺陷:当对象之间互相循环引用时,就会变的像“不死对象”;

    2.可达性分析算法

      在主流的商用程序语言(Java、C#,甚至包括前面提到的古老的Lisp)的主流实现中, 都是称通过可达性分析(Reachability Analysis)来判定对象是否存活的。这个算法的基本思 路就是通过一系列的称为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索所 走过的路径称为引用链(Reference Chain),当一个对象到GC Roots没有任何引用链相连 (用图论的话来说,就是从GC Roots到这个对象不可达)时,则证明此对象是不可用的。如 图3-1所示,对象object 5、object 6、object 7虽然互相有关联,但是它们到GC Roots是不可达 的,所以它们将会被判定为是可回收的对象

    在Java语言中,可作为GC Roots的对象包括下面几种:

    虚拟机栈(栈帧中的本地变量表)中引用的对象。

    方法区中类静态属性引用的对象。

    方法区中常量引用的对象。

    本地方法栈中JNI(即一般说的Native方法)引用的对象。

    3、引用

    • 强引用:“=”实现,引用只要还在,就不会被GC回收;
    • 软引用:SoftReference实现,在内存不足发生OOM之期,就回收掉该引用;
    • 弱引用:WeakReference实现,在下一次GC前,就回收掉该引用;
    • 虚引用:PhantomReference实现,在任何时候可能被回收,不过回收后可以收到系统的通知;

    4.生存还是死亡 (finalize方法自救)

    • 如果GC Roots 不可达,进行第一次标记;
    • 再看finalize()方法有没有被复写,有则先执行finalize()方法;
    1.    逃命方法:将自己关联到类变量之类或者某对象的成员变量的;
    2.    终身只有一次调用机会;
    • 接着GC进行第二次标记,如果没有逃脱,则回收;

    5.无用的类

    • 所有该类的实例已被回收
    • 该类的ClassLoad已被回收
    • 该类对应的java.lang.Class没有在任何地方被引用,不存在该类的反射

    三.垃圾回收算法

    1、标记——清除法

    • 方案:先标记,然后直接回收
    • 缺陷:产生大量碎片,不好分配大内存

    2、复制算法

    • 方案:将内存分为AB两块,回收时,将A块的对象全部复制到B,然后把未回收的上移,然后把已使用过的A全部清除;
    • 优点:实现简单,运行高效;
    • 缺陷:有一半处于无用状态,浪费;
    • HotSpot:通过 Eden:Surivor:Surivor=8:1:1的比例分配,这样只有10%的空间浪费;不足时,需要依赖其他内存分配担保;

    3、标记—整理算法

    • 方案:标记—清理之后,再整体上移;
    • 适应:适合老年代内存区使用

    4、分代收集算法

    • 新生代:使用复制算法
    • 老年代:使用“标记-清理”或者“标记—整理”算法

    四.垃圾收集器

    1、 Serial收集器

    • 这个收集器是一个单线程收集器,
    • 只会使用一个CPU或者一条收集线程进行垃圾收集工作
    • 其余的工作现场必须暂停,直到收集结束

    2、ParNew收集器

    • Serial收集器的多线程版本
    • 垃圾收集器线程和工作线程同时工作

    3、Paraller Scavenge收集器

    • 目标:达到一个可控的吞吐量
    • 吞吐量: 用户运行时间/(用户运行时间+垃圾回收时间)
    • GC自适应调节:调整参数提供最合适的停顿时间或者最大的吞吐量

    4、CMS收集器

    • 目标:最短回收停顿时间
    • 步骤:
    1. 初始标记
    2. 并发标记
    3. 重新标记
    4. 并发清除
    • 缺点:
    1. 对CPU资源非常敏感
    2. 无法处理浮动垃圾
    3. 基于“标记-清除”算法实现,碎片多

    5、G1 收集器

    • 并行与并发
    • 分代收集
    • 空间整合:
    1. 整体看:基于“标记-整理”算法
    2. 局部看:基于“复制”算法
    • 可预测停顿
    1. 有计划避免 Java 堆中进行全区域的垃圾收集

    6、GC日志

    33.125: [GC [DefNew: 3324k ->152k(3712k),0.0025925 secs] 3324k->152k(11904k),0.0031680 secs]
    • 33.125: GC发生时间
    • [GC:GC停顿类型,如果是 [Full GC
    • [DefNew: 垃圾回收器类型
    • 3324k ->152k(3712k): GC前内存区域已使用容量-> GC后内存区域已使用容量(内存区域总容量)
    • 3324k->152k(11904k): GC前Java堆已使用容量->GC后Java堆已使用容量
    • 0.0025925:内存区域GC所占用时间

    五.内存分配和回收策略

    最终都是给对象分配内存和回收分配给对象的内存

    • 对象优先在 Eden 分配
    • 大对象直接进入老年代
    • 长期存活的对象进入老年代
    • 动态对象年龄判定

    如果在一个 Survivor 空间中相同年龄所占内存大小占有一半,那么大于或者等于该年龄的对象直接进入老年代

    • 空间分配担保

    新生代的回收采用“复制算法”,如果没有足够的内存空间,需要老生代来担保,将一部分对象直接进入老年代,如果老年代空间还是不足,就有危险了。所以就根据以前进入老年代的对象容量大小的平均值来做个参考。通过 Fulll GC 对老年代进行一次GC,尽量腾出更多的空间。以防担保失败。

    • Minor Gc 和 Full GC
    1. Minor Gc:新生代的GC,很快
    2. Full GC:老年代的GC,慢10倍

    六.小结

      本篇了解引用的算法,由此去判断一个对象是"死”还是“活”,四种引用类型,由强至弱,生存能力越来越差,被 GC 回收的可能性也就越高。当然在一生中有唯一一次的自救机会,就是复写 finalize() 方法。进行垃圾回收时,会影响到性能。所以,出了各种回收算法以及垃圾回收器。这些各有优劣,只有适合当前环境的才是最好的。

  • 相关阅读:
    day06
    前端基础day02
    前端基础day01
    javascript基础语法
    day50 设置元素大小和边框
    day01 前端概述 html基础语法 html常用标签 css基本语法 css长度单位 css颜色单位 CSS常用属性-字体属性 CSS常用属性-文本属性 markdown的使用
    day 42 前端概述 HTML基础语法 HTML常用标签 CSS基本语法 CSS长度单位 CSS颜色单位 CSS选择器 CSS常用属性-字体属性 CSS常用属性文本属性 markdown的使用
    day41 pymysql模块介绍,增删改,简单查询以及sql注入问题,提交查询语句并且拿到查询结果,navicat工具,视图,触发器,事务,流程控制,函数,三种数据库开发模式,存储过程
    day40 增删改 单表查询的语法与关键字的执行优先级 简单查询,where关键字,group by关键字,having关键字,order by关键字,limit关键字,正则表达式,多表连接,子查询,查询语句的执行优先级
    NGUI动态创建UILabel
  • 原文地址:https://www.cnblogs.com/ganchuanpu/p/9428737.html
Copyright © 2020-2023  润新知