第三章 垃圾收集器和内存分配策略

第三章 垃圾收集器和内存分配策略

  1. 对象已死吗

    1. 引用计算方法
    2. 可达性分析算法
      1. 通过一些列的GC roots 对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径成为引用链,当一个对象到GC roots 没有任何引用链的则证明对象不可用的
      2. 虚拟机栈中的引用的对象
      3. 方法区中类静态属性引用的对象
      4. 方法去区中常量引用的对象
      5. 本地方法栈中JNI引用的对象
    3. 生存还是死亡
      1. 一次筛选,筛选是否有必要执行 finalize()方法
      2. 没有覆盖或者finalize()已经被调用过  视为没必要执行
      3. 放入一个F-Queue队列中
      4. 低优先级别的 Finalizer线程去执行他
      5. 对象逃脱死亡命运最后一次机会
      6. 如果要活,重新创建一个关联即可,譬如把自己赋值给某个对象的变量
      7. 如果标记,则移除队列,如果没有就回收了
      8. finalize()方法只会被系统执行一次,如果下一次 就无法自救了
      9. 应该尽量避免使用它 使用 try finnaly 更好
    4. 回收方法区
      1. 方法区  HotSpot的永久代
      2. 回收两部分内容:废弃常量和无用的类
      3. 无用的类的条件
        1. 所有实例已经回收
        2. 加载他的ClassLoader已经回收
        3. 该类对用Java.lang.Class 对象没有被引用
  2. 垃圾收集算法
    1. 标记-清除算法

      1. 先标记后回收
      2. 缺点
        1. 效率问题
        2. 空间问题,产生大量内存碎片
    2. 复制算法
      1. 等量划分为两块
      2. 将存活的对象移动到未使用的内存上
      3. 把使用过的一次清理
      4. 商业上不需要按照1:1分配,一块较大的Eden和两块较小的Survivor空间  使用Eden和一块 Survivor,回收是将存活的对象Eden和Survivor拷贝到另一块Survivor中,最后清理掉刚才用的人,
    3. 标记整理算法
      1. 前面和标记清除方法一样,后面不是直接对可回收对象进行清理而是让所有存活的对象都向一端移动,然后直接清理边界外的内存
    4. 分代手机算法
      1. 当前商业都是按照这个方法
      2. 根据存活周期不同分为几块
      3. 分为新生代和老年代
      4. 新生代 如有大批对象死去 就用复制算法
      5. 老年代存活率较高  就用 标记清理或者整理算法
  3. HotSpot的算法实现
    1. 枚举根节点

      1. 可达性分析中的GCRoots 消耗很多事件
      2. 体现在GC停顿上,因为这项分析工作必须能确保一直的快照中进行,看起来像被冻结的时间点
      3. 目前主流java虚拟机为准确式GC 不需要一个不漏检查完所有
    2. 安全点
      1. 在特定的位置记录这些信息生成OOPMap
      2. 不能太少以至于GC等待时间太长,也不能太多导致频繁GC
      3. 抢先式终端和自主中断(让线程轮训判断)
    3. 安全区域
      1. 安全点保证了程序执行时在不太长的时间内就会遇到可进入GC的SafePoint,保证程序执行的时候,在不执行(sleep)的时候无法响应中断请求,这首就需要安全区域来解决
      2. 定义:安全区域是指一段代码片段之中,引用关系不会发生变化,任何地方GC都是安全的,扩展了的安全点
  4. 垃圾收集器
    1. 种类

      1. Serial收集器

        1. Serial 连续的 连载的
        2. 发展最悠久的收集器
        3. 必须暂停其他所有的线程  Stop the world
        4. 没办法 妈妈扫地例子
        5. 虚拟机运行在Client模式下的默认新生代收集器
        6. 优点,简单而高效,几十毫秒到一百多毫秒
      2. ParNew收集器
        1. 其实就是Serial收集器的多线程版本
        2. Server模式下首选新生代收集器
        3. -XX:-UseParNewGC 指定使用 ParNew收集器
        4. 单CPU下不见得比Serial强,有开销,默认线程与CPU数量相同 使用-XX:ParallelGCThreads参数指定数量
      3. Parallel Scavenge(清除污物;打扫) 收集器
        1. 新生代收集器 使用复制算法 多线程收集器
        2. 不同点
          1. CMS收集器关注尽可能缩短停顿时间 在gc的时候
          2. 它关注一个可控制的吞吐量 吞吐量=运行用户时间/(运行用户时间 +垃圾收集时间)
          3. 精准控制吞吐量 最大垃圾停顿时间 -XX:MaxGCPauseMillis 吞吐量 -XX:GCTimeRatio参数
          4. 停顿时间缩短是以牺牲吞吐量和新生代空间换取的
            1. 导致垃圾收集频繁
        3. 吞吐量优先收集器
        4. -XX:UseAdaptiveSizePolicy 开关参数 指定后 不需要指定新生代大小 -Xmn Eden Survivor 比率 -XX:SurvivorRatio  会动态调整 自适应调节策略
      4. Serial Old收集器
        1. Serial 老年版本 单线程
        2. Client模式下虚拟机使用
        3. 在Sever下的两个用途
          1. JDK1.5 和以上 与 Parallel Scavenge搭配使用
          2. CMS的后背员,发生Concurrent Mode Failure时候使用
      5. Parallel Old 收集器
        1. Parallel Scavenge 老年代版本
        2. 多线程  标记整理手机算法
        3. JDK1.6 以前很尴尬,Parallel Scavenge 只能与 Serial Old 结合使用 影响吞吐量
        4. 在注重吞吐量以及CPU资源敏感的场合,应该考虑Parallel Scavenge 和 Parallel Old
      6. CMS(Concurrent Mark Sweep) 收集器
        1. 获得最短回收停顿时间为目标的收集器
        2. 互联网站、B/S架构服务器上,注重响应速度,良好体验
        3. 标记清除算法
        4. 分为四个步骤
          1. 初始标记  需要Stop world
          2. 并发标记  与用户线程并行
          3. 重新标记 需要Stop world
          4. 并发清除 与用户线程并行
        5. 并发低停顿收集器 缺点有
          1. CPU资源敏感,并发时占用一定资源,导致应用程序变慢,总吞吐量变低
          2. 无法处理浮动垃圾  可能出现Concurrent Mode Failure 导致 Ful GC
          3. 浮动垃圾 并发遗留的,不能全部填满再收集,要预留一部分
      7. G1(Garbage-First)收集器 
        1. 最前沿成果之一
        2. 面向服务器应用的垃圾收集器  可以替换掉 CMS 收集器
        3. 特点有
          1. 并行与并发
          2. 分代收集
          3. 标记-整理    规整可用内存,不会提前出发Full GC
          4. 可预测的停顿
            1. 分为大小相同的独立区域
            2. 新生代老年代不在物理隔离,区域的集合  需要要连续
            3. 避免整个区域的垃圾收集
            4. 跟踪价值大小,维护优先列表 有限回收价值大的区域
      8. 理解GC日志
        1. DefNew Default New Generation 默认收集器 使用 Serial收集器
        2. ParNew  Parallel New Generation
        3. PSYoungGen Parallel Scavenge
      9. 垃圾收集器参数
        1. SuvivorRatio 新生代中 Eden 区域 和Survivor 区域的容量比值
        2. MaxTenuringThreshold 晋升到老年代的年龄  经历过一次MonitorGC后 年龄加1
  5. 内存分配与回收策略
    1. 内容

      1. 内存分配

        1. 主要分配在Eden区域,启动本地贤臣分配缓冲,分派在TLAB上
        2. 少数情况在老年代中
        3. 当Eden内存不够的时候,发起一次Monitor GC
        4. 提供了 -XX:+PrintGCDetails 参数 打印gc日志,系统推出的时候输出内存区域分配
        5. 如果 Eden 不够 Survivor 内存 都不够的时候 直接分配担保机制 提前转移到老年代中。
        6. Monitor GC 发生在新生代的垃圾收集动作  java对象朝生夕灭,非常频繁,速度快
        7. 老年代GC(Major GC  Full GC)出现此GC 一般伴随一次Monitor GC 表慢10倍以上
        8. Java -verbose:gc 中参数-verbose:gc 表示输出虚拟机中GC的详细情况.
        9. 写程序避免使用朝生夕灭的大对象  使用大对象导致还有不少空间时就提前出发垃圾收集器
      2. 长期存活的对象进入老年代   -XX:MaxTenuringThreshold 晋升老年代的年龄法制
      3. 动态对象年龄判断: 相同年龄所有对象的大小综合大于Survivor空间的一半,也会进入老年代。
      4. 空间分配担保
        1. 检查老年代最大可用空间是否大于新生代对象总空间
        2. 成立则是安全的
        3. 不成立 查看 HandlePromotionFailure是否允许担保失败
        4. 如果允许,查看大小是否大与历次晋升的平均大小
        5. 大与 则 尝试  有风险
        6. 小于,或者不允许冒险,则进行Full GC
时间: 2024-12-23 01:45:44

第三章 垃圾收集器和内存分配策略的相关文章

第三章 垃圾收集器与内存分配策略

书中笔记: 也许并不会死: 要宣告回收一个对象死亡,至少要经历两次标记过程: 当可达性分析发现一个对象不可达的时候,将标记第一次并进行筛选,筛选的条件是此对象是否有必要执行finalize()方法,当对象没有覆盖finalize或者已被调用过,则虚拟机认为此对象没必要执行finalize,  如果判断有必要执行,则此对象将会被放入一个F-Queue队列中,之后会被一个优先级比较低的Finalizer线程去调用,但是并不会等待他执行完毕,因为此对象的finalize并不可靠,可能会死循环之类的,如

第三章垃圾收集器与内存分配策略

3.2对象死亡的判断方法 3.2.1引用计数法 给对象添加一个引用计数器,每当一个地方引用它就+1,引用失效就-1,当计数器为0时就表示对象已经死亡. 缺点是无法解决循环引用问题 3.2.2可达性分析 将GC root作为根节点向下遍历,无法遍历到的对象(GC Root到这个对象不可达)就表示该对象已经死亡. 3.2.3对象的自救 已经死亡的对象会被第一次标记,然后进行筛选,筛选出是否有必要执行finalize()方法,如果对象有并且是第一次被调用那么对像将被放在F-Queue队列中,等待虚拟机

《深入理解JAVA虚拟机》----------第三章 垃圾收集器与内存分配策略,读后感(中)

1.垃圾收集器 1.1 Serial收集器 这个收集器是一个单线程的收集器,它在进行垃圾收集时,必须暂停其他所有的工作线程. 它是虚拟机运行在Client模式下的默认新生代收集器,它简单而高效. 1.2 ParNew收集器 其实就是Serial收集器的多线程版本,目前只有它能与CMS收集器配合工作. 原文地址:https://www.cnblogs.com/technologykai/p/10622586.html

[深入理解JVM虚拟机]第3章-垃圾收集器、内存分配策略

垃圾收集器 判断对象是否需存活 回收堆 判断对象是否存活: 方法一:引用计数法.对象被引用一次就+1,当为0时回收对象.缺点:无法解决循环引用问题. 方法二:可达性分析算法.记录当前对象是否有和GC Roots中对象的引用链.(其中,可以作为GCRoots对象的有:虚拟机栈中引用的对象.方法去中类静态属性引用的对象.方法区中常量引用的对象.本地方法栈中引用的对象.) 不可达对象并不是一定被垃圾收集的,当这个对象有必要执行finalize()并finalize里自己和某个对象建立关联,即可在第二次

垃圾收集器与内存分配策略(三)之HotSpot的算法实现

垃圾收集器与内存分配策略(三)--HotSpot的算法实现 Java JVM 垃圾回收 在HotSpot虚拟机上实现这些算法时,必须对算法的执行效率有着严格的考量,才能保证虚拟机高效地运行. 1. 枚举根节点 采用可达性分析从GC Roots节点中找引用链为例 存在的缺点: 1.在前面找出还存活对象时,采用可达性分析从GC Roots节点中找引用链时,可作为GC Roots的节点主要在全局性的引用(方法区的常量或类静态属性引用)与执行上下文(虚拟机栈栈帧中的本地变量表或本地方法栈中的Native

Java虚拟机垃圾收集器与内存分配策略

Java虚拟机垃圾收集器与内存分配策略 概述 那些内存需要回收,什么时候回收,如何回收是GC需要完成的3件事情. 程序计数器,虚拟机栈与本地方法栈这三个区域都是线程私有的,内存的分配与回收都具有确定性,内存随着方法结束或者线程结束就回收了. java堆与方法区在运行期才知道创建那些对象,这部分内存分配是动态的,本章笔记中分配与回收的内存指的就是:java堆与方法区. 判断对象已经死了 引用计数算法:给对象添加一个引用计数器,每当有一个地方引用它,计数器+1;引用失败,计数器-1.计数器为0则改判

垃圾收集器以及内存分配策略

垃圾回收 垃圾回收的三个问题: 哪些内存需要回收? 什么时候回收? 如何回收? 1.哪些对象需要回收? 判断对象是否存活的办法: 引用计数算法:给对象中添加一个引用计数器,有一个地方引用就+1,引用失效就-1.只要计数器为0则对象已死. 优点:简单易实现: 缺点:无法解决对象之间相互引用的问题.(JVM也因为此种原因没有使用它) 根搜索算法: 通过选取出一个GC Roots对象,已它作为起始点,如果对象不可达,则对象已死. GC Roots对象: 虚拟机栈中引用的对象 方法区中类静态属性引用的对

深入理解java虚拟机----->垃圾收集器与内存分配策略(下)

1.  前言 内存分配与回收策略 JVM堆的结构分析(新生代.老年代.永久代) 对象优先在Eden分配 大对象直接进入老年代 长期存活的对象将进入老年代 动态对象年龄判定 空间分配担保  2.  垃圾收集器与内存分配策略 Java技术体系中所提倡的自动内存管理最终可以归结为自动化地解决两个问题: 给对象分配内存; 回收分配给对象的内存. 对象的内存分配,往大方向上讲就是在堆上的分配,对象主要分配在新生代的Eden区上.少数也可能分配在老年代,取决于哪一种垃圾收集器组合,还有虚拟机中的相关内存的参

垃圾收集器与内存分配策略(二)

垃圾收集算法简介 1.标记-清除算法       标记-清除算法主要分为“标记”和“清除”两个阶段:首先标记出所有需要回收的对象,在标记完成后统一进行回收.对象的标记过程在垃圾收集器与内存分配策略(一)中已经介绍过. 存在的问题:一是效率问题,标记和清除的效率都不高:二是空间问题,标记清除之后会产生大量不连续的内存碎片,空间碎片太多可能会导致以后在程序运行过程中需要分配较大对象时无法找到足够的内存而不得不提前触发另一次垃圾收集动作. 2.复制算法       复制算法:它将内存按照容量划分为大小