JVM之垃圾回收

 


哪些内存需要回收?即如何判定哪些对象是垃圾

  1. 引用计数法
    • 做法:为每个对象维护一个引用它的数量cnt,比如放到对象头中,如果新增对他的引用cnt就+1,如果当某个引用失效时cnt就-1
    • 缺点:当两个对象互相引用时,无法回收
  2. 可达性分析法
    • 做法:一系列称为“GC Roots”的根对象作为起始节点集,从这些节点开始,根据引用关系向下搜索。如果某一对象无法从“GC Roots”中向下搜索到,那个该对象就是不可达的,也就是可以被回收掉的
    • “GC Roots”中包含:
      1. 在虚拟机栈(栈帧中的本地变量表)中引用的对象,譬如各个线程被调用的方法堆栈中使用到的参数、局部变量、临时变量等
      2. 在方法区中类静态属性引用的对象,譬如Java类的引用类型静态变量
      3. 在方法区中常量引用的对象,譬如字符串常量池(String Table)里的引用
      4. 在本地方法栈中JNI(即通常所说的Native方法)引用的对象
      5. Java虚拟机内部的引用,如基本数据类型对应的Class对象,一些常驻的异常对象(比如NullPointExcepiton、OutOfMemoryError)等,还有系统类加载器
      6. 所有被同步锁(synchronized关键字)持有的对象
      7. 反映Java虚拟机内部情况的JMXBean、JVMTI中注册的回调、本地代码缓存等
      8. 其他...

四种引用

finalize()

回收方法区
废弃的常量和不在被使用的类

垃圾回收算法

为什么目前商业的垃圾收集器,大多都遵循了“分代收集”的理论?
这里的加粗部分

  1. 标记-清除算法

    • 做法:标记可以回收的对象(也可以标记存活的对象),再做清除
    • 缺点:
      1. 效率不稳定,如果有大量的对象需要回收,则需要消耗很多时间
      2. 会产生内存碎片,导致分配分配大对象时无法分配(但总的内存空间是够的),再触发垃圾回收。这里和OS的内存分配联系一下
  2. 标记-复制算法

    • 做法:将可用的内存分为两部分,每一次将存活的对象复制到另一个部分
    • 优点:
      1. 没有内存碎片的问题
    • 缺点:
      1. 如果一次GC后发现有大量的对象存活,就需要移动大量的内存(但这种场景一般不会出现)
      2. 可用的内存直接少了一半
    • 补充:
      1. IBM统计:新生代中的对象有98%熬不过第一轮收集,所以分成的两部分并不需要按照1:1的比例
      2. HotSpot虚拟机默认Eden和Survivor的大小比例是8∶1,当然也有可能出现GC后Survivor区放不下了,那么这个时候就需要老年代去兜底。既然这样很显然老年代是不能使用这种算法的,因为没有内存区域再去给他兜底了(除非再顶一个新的内存空间)

    大多数商用的虚拟机采用该方法回收新生代

  3. 标记-整理算法

    • 做法:第一步和标记-清除算法一致,只是标记完后标记-整理算法是让所有存活的对象都向内存空间一端移动,然后直接清理掉边界以外的内存
    • 优点:
      1. 没有了内存碎片
    • 缺点:
      1. 相比于直接清除,多了一步整理的过程,所以会更加耗时,是个非常重的操作,此时会暂停用户的应用程序,也就是Stop the world
    • 补充:
      1. 虽然在垃圾回收阶段耗时增加了,但是由于没有了内存碎片,在给对象分配内存时的耗时就会减少(假如我在很多的内存碎片中分配一个大的对象,还需要维护每一个内存碎片的起始位置等等),所以一个程序整体的吞吐量是增加了的。
      2. HotSpot虚拟机里面关注吞吐量的Parallel Scavenge收集器是基于标记-整理算法的,而关注延迟的CMS收集器则是基于标记-清除算法的

    采用该方法回收老年代

HotSpot实现细节

安全点

记忆表与卡表

垃圾回收器

  1. 新生代:
    • Serial(标记复制)
    • ParNew(标记复制)
    • Parallel Scavenge(标记复制)
  2. 老年代:
    • CMS(标记清除)
    • Serial Old(标记整理)
    • Parallel Old(JDK6,标记整理)

  1. Serial
    • 使用:可以和Serial Old或CMS配合使用
    • 做法:首先Serial是一个单线程收集器,意味着不管用户线程有多少个,当都走到了安全点,只有一个线程会执行垃圾回收的操作
    • 使用场景:客户端模式(分配的内存不大),比如桌面应用,因为它简单且单线程没有上下文切换的成本,同时占用的内存是最少的
  2. ParNew
    • 使用:可以和Serial Old或CMS配合使用
    • 做法:其实就是Serial的多线程版本
    • 使用场景:服务端模式,在JDK5中使用CMS来收集老年代的时候,新生代只能选择ParNew或者Serial收集器中的一个,可以说直到CMS的出现才巩固了ParNew的地位。使用CMS时,默认CMS+ParNew
  3. Parallel Scavenge
    • 使用:可以和Serial Old或Parallel Old配合使用
    • 做法:可以控制吞吐量(val=useruser+gc
      1. -XX:MaxGCPauseMillis参数允许的值是一个大于0的毫秒数,收集器将尽力保证内存回收花费的
        时间不超过用户设定值
      2. -XX:GCTimeRatio参数的值则应当是一个大于0小于100的整数,默认为99,最大1%的垃圾回收时间
      3. -XX:+UseAdaptiveSizePolicy,当这个参数被激活之后,就不需要人工指定新生代的大小(-Xmn)、Eden与Survivor区的比例(-XX:SurvivorRatio)、晋升老年代对象大小(-XX:PretenureSizeThreshold)等细节参数了,虚拟机会根据当前系统的运行情况收集性能监控信息,动态调整这些参数以提供最合适的停顿时间或者最大的吞吐量
    • 使用场景:手动优化困难,可以使用该垃圾回收器。自适应调节策略也是Parallel Scavenge收集器区别于ParNew收集器的一个重要特性

  1. Serial Old
    • 做法:Serial Old是Serial收集器的老年代版本,所以原理类似
    • 使用场景:
      1. 与Parallel Scavenge一起使用
      2. 作为CMS收集器发生失败时的后备预案,在并发收集发生Concurrent Mode Failure时使用
  2. Parallel Old
    • 使用场景:由于之前Parallel Scavenge只能和Serial Old配合使用,所以性能被老年代的垃圾回收器拖累,使得使用Parallel Scavenge收集器也未必能在整体上获得吞吐量最大化的效果。同样,由于单线程的老年代收集中无法充分利用服务器多处理器的并行处理能力,在老年代内存空间很大而且硬件规格比较高级的运行环境中,这种组合的总吞吐量甚至不一定比ParNew加CMS的组合来得优秀。在吞吐量优先的场景中可以使用Parallel Scavenge+Parallel Old
  3. CMS(Concurrent Mark Sweep)
    • 说明:CMS收集器是一种以获取最短回收停顿时间为目标的收集器
    • 做法:
      1. 初始标记(stop the world):标记GC Roots能直接关联到的对象,速度很快
      2. 并发标记:gc线程和用户线程同时执行,速度较长但是由于不会停顿用户线程,所以反映到用户侧影响不大
      3. 重新标记(stop the world):意思就是gc线程可能认为某些节点已经不可达了,但是用户线程又增加了对某些不可达对象的引用,因此这对象不能被回收掉,这一步主要就是做这个工作,停顿时间会比第一步稍长,但是远小于第二步。
      4. 并发清理,因为不需要移动所以不用stop the world
    • 问题:
      1. 虽然第二步和第四步不需要stop the world,但是因为还需要占线程所以会影响用户的吞吐量
      2. 浮动垃圾
      3. 老年代需要留一部分空间

  1. G1(Garbage First)

有点怀疑了...









说明

===================================

仅作为校招时的《个人笔记》,详细内容请看【参考】部分

===================================

参考

  1. 《深入理解Java虚拟机》
  2. 《垃圾回收的算法与实现》
posted @   optimjie  阅读(6)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端
点击右上角即可分享
微信分享提示