【JVM学习笔记】垃圾收集器与内存分配策略

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

对象已死?(判断对象是否可以回收)

引用

  • reference类型的数据中存储的数值代表的是另一块内存的起始地址

    • 强引用:代码中的引用赋值 例如 new对象;意义:对象不会被回收
    • 软引用:还有用非必须的对象;意义:在系统将要发生内存溢出前回收
    • 弱引用:非必须对象;意义:每次垃圾回收时都会被清理
    • 虚引用:最弱的一种引用;意义:可以让一个对象被回收时收到一个系统通知

引用计数算法

  • 在对象中添加一个引用计数器,被引用加一,引用失效减一,为零就不会再使用可以回收
  • 优点:原理简单,效率高
  • 缺点:实用性不强,例如 很难解决对象间的互相循环引用的问题

可达性分析算法

  • 判断某个对象到GC Roots间有没有引用链相连,如果没有就说明对象不可达、不再使用可以回收

  • GC Roots

    • 虚拟机栈的本地变量表中引用的对象
    • 方法区中类静态属性引用的对象
    • 方法区中常量引用的对象
    • 本地方法栈中JNI(Native方法)引用的对象
    • java虚拟机内部的引用,如基本数据类型对应的Class对象,常驻的异常对象,类加载器
    • 同步锁持有的对象
    • 反应虚拟机内部情况的JMXBean、JVMTI中注册的回调、本地代码缓存等

生存还是死亡(判断对象是否真的能被回收)

  • 至少要经历两次标记(判断),如果第一次被标记成不可达,但是在第二次标记前又与GC Roots建立了链接就不会被清理

回收方法区

  • 《java虚拟机规范》不强制方法区实现垃圾收集
  • 方法区垃圾收集性价比比较低
  • 主要回收废弃的常量和不再使用的类型(类型指加载到内存中的Class)

垃圾收集算法

引用计数式垃圾收集(直接垃圾收集)

追踪式垃圾收集(间接垃圾收集)(主流)

  • 分代收集理论

    设计原则:收集器应该将java堆划分出不同区域,然后将回收对象依据其年龄分配到不同的区域之中存储

    • 弱分代假说:绝大多数对象都是朝生夕死的

    • 强分代假说:熬过越多次垃圾收集过程的对象越你难以死亡

    • 分代

      • 新生代
      • 老年代
    • 跨分代引用假说:存在相互引用关系的对象应该倾向于同生同死,跨代引用占比较少。

      • 存在问题:当扫描新生代对象时如果有跨代引用还需要扫描整个老年代,成本较高

        • 解决办法:新生代建立一个全局数据结构(记忆集),这个结构将老年代划分成若干小块,标识出老年代的哪一块内存存在跨代引用。Minor GC时只有包含了跨代引用的小块内存里的对象才会被加入到GC Roots进行扫描,而不用扫描整个老年代
  • 标记-清除算法:标记后清除被标记的对象

    • 缺点:1、执行效率不稳定(受要标记的目标对象数量的限制);2、内存空间碎片化(产生不连续的内存碎片)
  • 标记-复制算法:将内存划分为大小相等的两块,每次只用其中一块,当内存用完了就将存活对象复制到另一块,然后将已使用的内存一次清理掉

    • 缺点:空间浪费太严重
    • 新生代优先采用此算法,而老年代不会使用这种方法,因为新生代98%对象都是朝生夕死的,这种情况实现简单、效率高
  • 标记-整理算法:先标记,让存活对象都移动到内存一端,然后清理掉边界以外的内存

经典垃圾收集器

Serial收集器

  • 单线程收集器
  • 优点:简单高效、内存消耗最小
  • 缺点:工作时必须“Stop The World”,用户体验差

ParNew收集器

  • Serial收集器多线程并行版本
  • HotSpot虚拟机中第一款退出历史舞台的垃圾收集器,只能和CMS配合使用而CMS将会替代CMS

Parallel Scavenge收集器

  • 多线程,基于标记-复制算法
  • 设计目标:达到一个可控的吞吐量(也就是控制垃圾回收所占用的时间)

Serial Old收集器

  • Serial的老年代版本
  • 单线程,基于标记整理算法

Parallel Old收集器

  • Parallel Scavenge收集器老年代版本
  • 多线程,基于标记-整理算法

CMS收集器

  • 目标:为了获取最短回收停顿时间

  • 多线程,基于标记-清除算法

  • 缺点:1、处理器资源敏感,会占用一部分资源导致程序变慢,总吞吐量降低。2、无法处理浮动垃圾,可能导致full gc发生。3、无法处理空间碎片,只能依靠full gc

    浮动垃圾:CMS标记和清理阶段用户线程会同时运行并产生新的垃圾,因为有些垃圾在标记后产生所以本次无法清理,只能等到下次。

Garbage First收集器(G1)

  • 将堆内存划分为多个大小相等的独立区域(Region),每个区域都可以根据需要扮演新生代的Eden空间、Survivor空间或老年代空间,每次回收时G1会判断那块回收性价比最高,收益最大;Region中设有Humongous区域,用来存储大对象(超过Region一半的对象),而超级大对象会被存放在多个连续的Humongous区域

  • 与CMS比较

    • 优势:1、不会产生垃圾碎片;2、创新性设计带来较多红利:可以指定最大停顿时间,分区域的内存布局,按收益动态确定回收集
    • 弱势:1、占用内存多、负载率高

基础故障处理工具

jps:虚拟机进程状况工具,主要用来查看进行的唯一ID

jstat: 虚拟机统计信息监视工具,主要用于查看虚拟机各种运行状态信息

jinfo:java配置信息工具,主要使用-sysprops 打印System.getProperties()的内容

jmap:java内存映像工具,主要用于生成堆转储快照

jhat:虚拟机堆转储快照分析工具,图形化工具更适合这个工作 所以这个命令用处不大

jstack:java堆栈跟踪工具,主要用于生成虚拟机当前时刻线程快照,例如可以查看没有相应的线程在后台干什么

内存回收策略

在经典分代设计下,新生对象通常会分配在新生代中,少数情况下也可能直接分配在老年代

对象优先在新生代Eden区域分配

大对象直接进入老年代

长期存活对象进入老年代

  • Eden中的对象经过一次GC仍然存活并且能被Survivor容纳就会被转移到Survivor中,并将对象年龄设置为1,对象在Survivor中每熬过一次GC就增加一岁,年龄增加到15(默认 可以设置)时进入老年代

动态对象年龄判定

  • HotSpot虚拟机并不是永远等到对象年龄达到标准才晋升到老年代,如果Survivor空间中的相同年龄所有对象大小的总和大于Survivor空间的一半,年龄大于或等于该年龄的对象就直接进入老年代

选择合适的垃圾收集器

垃圾收集器工作内容

  • 垃圾收集、堆内存的管理与布局、对象的分配、与解释器的协作、与编译器的协作,与监控子系统的协作等等

应用只要运行数分钟甚至数秒,只要虚拟机能正确分配内存,在堆耗尽之前就会退出

  • Epslion收集器,不进行垃圾回收,但负载极小

收集器的权衡

  • 应用程序的关注点

    • 吞吐量
    • 延迟
    • 内存占用

虚拟机及垃圾收集器日志

  • 1、查看GC基本信息:jdk9以前 -XX:+PrintGC,9以后 -Xlog:gc
  • 2、查看GC详细信息:9以前 -XX:+PrintGCDetails,9以后 -X-log:gc*
  • 3、查看GC前后堆、方法区可用容量变化:9以前-XX:+PrintHeapAtGC,9以后 -Xlog:gc+heap=debug
  • 4、查看GC过程中用户线程并发时间以及停顿的时间:9以前-XX:Print-GCApplicationConcurrentTime 及 -XX:+PrintGCApplicatiionStoppedTime,9以后 -Xlog:safepoint
  • 只列出一些常用的命令
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值