第三章 垃圾收集器和内存分配策略
Posted 双宝的博客
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第三章 垃圾收集器和内存分配策略相关的知识,希望对你有一定的参考价值。
第三章 垃圾收集器和内存分配策略
- 对象已死吗
- 引用计算方法
- 可达性分析算法
- 通过一些列的GC roots 对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径成为引用链,当一个对象到GC roots 没有任何引用链的则证明对象不可用的
- 虚拟机栈中的引用的对象
- 方法区中类静态属性引用的对象
- 方法去区中常量引用的对象
- 本地方法栈中JNI引用的对象
- 生存还是死亡
- 一次筛选,筛选是否有必要执行 finalize()方法
- 没有覆盖或者finalize()已经被调用过 视为没必要执行
- 放入一个F-Queue队列中
- 低优先级别的 Finalizer线程去执行他
- 对象逃脱死亡命运最后一次机会
- 如果要活,重新创建一个关联即可,譬如把自己赋值给某个对象的变量
- 如果标记,则移除队列,如果没有就回收了
- finalize()方法只会被系统执行一次,如果下一次 就无法自救了
- 应该尽量避免使用它 使用 try finnaly 更好
- 回收方法区
- 方法区 HotSpot的永久代
- 回收两部分内容:废弃常量和无用的类
- 无用的类的条件
- 所有实例已经回收
- 加载他的ClassLoader已经回收
- 该类对用Java.lang.Class 对象没有被引用
- 垃圾收集算法
- 标记-清除算法
- 先标记后回收
- 缺点
- 效率问题
- 空间问题,产生大量内存碎片
- 复制算法
- 等量划分为两块
- 将存活的对象移动到未使用的内存上
- 把使用过的一次清理
- 商业上不需要按照1:1分配,一块较大的Eden和两块较小的Survivor空间 使用Eden和一块 Survivor,回收是将存活的对象Eden和Survivor拷贝到另一块Survivor中,最后清理掉刚才用的人,
- 标记整理算法
- 前面和标记清除方法一样,后面不是直接对可回收对象进行清理而是让所有存活的对象都向一端移动,然后直接清理边界外的内存
- 分代手机算法
- 当前商业都是按照这个方法
- 根据存活周期不同分为几块
- 分为新生代和老年代
- 新生代 如有大批对象死去 就用复制算法
- 老年代存活率较高 就用 标记清理或者整理算法
- 标记-清除算法
- HotSpot的算法实现
- 枚举根节点
- 可达性分析中的GCRoots 消耗很多事件
- 体现在GC停顿上,因为这项分析工作必须能确保一直的快照中进行,看起来像被冻结的时间点
- 目前主流java虚拟机为准确式GC 不需要一个不漏检查完所有
- 安全点
- 在特定的位置记录这些信息生成OOPMap
- 不能太少以至于GC等待时间太长,也不能太多导致频繁GC
- 抢先式终端和自主中断(让线程轮训判断)
- 安全区域
- 安全点保证了程序执行时在不太长的时间内就会遇到可进入GC的SafePoint,保证程序执行的时候,在不执行(sleep)的时候无法响应中断请求,这首就需要安全区域来解决
- 定义:安全区域是指一段代码片段之中,引用关系不会发生变化,任何地方GC都是安全的,扩展了的安全点
- 枚举根节点
- 垃圾收集器
- 种类
- Serial收集器
- Serial 连续的 连载的
- 发展最悠久的收集器
- 必须暂停其他所有的线程 Stop the world
- 没办法 妈妈扫地例子
- 虚拟机运行在Client模式下的默认新生代收集器
- 优点,简单而高效,几十毫秒到一百多毫秒
- ParNew收集器
- 其实就是Serial收集器的多线程版本
- Server模式下首选新生代收集器
- -XX:-UseParNewGC 指定使用 ParNew收集器
- 单CPU下不见得比Serial强,有开销,默认线程与CPU数量相同 使用-XX:ParallelGCThreads参数指定数量
- Parallel Scavenge(清除污物;打扫) 收集器
- 新生代收集器 使用复制算法 多线程收集器
- 不同点
- CMS收集器关注尽可能缩短停顿时间 在gc的时候
- 它关注一个可控制的吞吐量 吞吐量=运行用户时间/(运行用户时间 +垃圾收集时间)
- 精准控制吞吐量 最大垃圾停顿时间 -XX:MaxGCPauseMillis 吞吐量 -XX:GCTimeRatio参数
- 停顿时间缩短是以牺牲吞吐量和新生代空间换取的
- 导致垃圾收集频繁
- 吞吐量优先收集器
- -XX:UseAdaptiveSizePolicy 开关参数 指定后 不需要指定新生代大小 -Xmn Eden Survivor 比率 -XX:SurvivorRatio 会动态调整 自适应调节策略
- Serial Old收集器
- Serial 老年版本 单线程
- Client模式下虚拟机使用
- 在Sever下的两个用途
- JDK1.5 和以上 与 Parallel Scavenge搭配使用
- CMS的后背员,发生Concurrent Mode Failure时候使用
- Parallel Old 收集器
- Parallel Scavenge 老年代版本
- 多线程 标记整理手机算法
- JDK1.6 以前很尴尬,Parallel Scavenge 只能与 Serial Old 结合使用 影响吞吐量
- 在注重吞吐量以及CPU资源敏感的场合,应该考虑Parallel Scavenge 和 Parallel Old
- CMS(Concurrent Mark Sweep) 收集器
- 获得最短回收停顿时间为目标的收集器
- 互联网站、B/S架构服务器上,注重响应速度,良好体验
- 标记清除算法
- 分为四个步骤
- 初始标记 需要Stop world
- 并发标记 与用户线程并行
- 重新标记 需要Stop world
- 并发清除 与用户线程并行
- 并发低停顿收集器 缺点有
- CPU资源敏感,并发时占用一定资源,导致应用程序变慢,总吞吐量变低
- 无法处理浮动垃圾 可能出现Concurrent Mode Failure 导致 Ful GC
- 浮动垃圾 并发遗留的,不能全部填满再收集,要预留一部分
- G1(Garbage-First)收集器
- 最前沿成果之一
- 面向服务器应用的垃圾收集器 可以替换掉 CMS 收集器
- 特点有
- 并行与并发
- 分代收集
- 标记-整理 规整可用内存,不会提前出发Full GC
- 可预测的停顿
- 分为大小相同的独立区域
- 新生代老年代不在物理隔离,区域的集合 需要要连续
- 避免整个区域的垃圾收集
- 跟踪价值大小,维护优先列表 有限回收价值大的区域
- 理解GC日志
- DefNew Default New Generation 默认收集器 使用 Serial收集器
- ParNew Parallel New Generation
- PSYoungGen Parallel Scavenge
- 垃圾收集器参数
- SuvivorRatio 新生代中 Eden 区域 和Survivor 区域的容量比值
- MaxTenuringThreshold 晋升到老年代的年龄 经历过一次MonitorGC后 年龄加1
- Serial收集器
- 种类
- 内存分配与回收策略
- 内容
- 内存分配
- 主要分配在Eden区域,启动本地贤臣分配缓冲,分派在TLAB上
- 少数情况在老年代中
- 当Eden内存不够的时候,发起一次Monitor GC
- 提供了 -XX:+PrintGCDetails 参数 打印gc日志,系统推出的时候输出内存区域分配
- 如果 Eden 不够 Survivor 内存 都不够的时候 直接分配担保机制 提前转移到老年代中。
- Monitor GC 发生在新生代的垃圾收集动作 java对象朝生夕灭,非常频繁,速度快
- 老年代GC(Major GC Full GC)出现此GC 一般伴随一次Monitor GC 表慢10倍以上
- Java -verbose:gc 中参数-verbose:gc 表示输出虚拟机中GC的详细情况.
- 写程序避免使用朝生夕灭的大对象 使用大对象导致还有不少空间时就提前出发垃圾收集器
- 长期存活的对象进入老年代 -XX:MaxTenuringThreshold 晋升老年代的年龄法制
- 动态对象年龄判断: 相同年龄所有对象的大小综合大于Survivor空间的一半,也会进入老年代。
- 空间分配担保
- 检查老年代最大可用空间是否大于新生代对象总空间
- 成立则是安全的
- 不成立 查看 HandlePromotionFailure是否允许担保失败
- 如果允许,查看大小是否大与历次晋升的平均大小
- 大与 则 尝试 有风险
- 小于,或者不允许冒险,则进行Full GC
- 内存分配
- 内容
以上是关于第三章 垃圾收集器和内存分配策略的主要内容,如果未能解决你的问题,请参考以下文章