JVM堆内存分配及垃圾回收算法

本文介绍了Java堆内存的划分,包括新生代、老年代和元空间,并详细讲解了Minor GC和Full GC的工作原理及触发条件。此外,文章还探讨了多种垃圾回收算法,如标记-清除、复制、标记整理和分代收集,分析了它们的优缺点和应用场景。

堆内存划分

  • Java堆是被所有线程共享的一块内存区域,虚拟机又把堆内存划分为新生代、老年代、永久代三块区域。
  • 新生代(Young)又被划分为三个区域:Eden、From Survivor、To Survivor
  • 默认情况下 新生代 ( Young ) 与老年代 ( Old ) 的比例的值为 1:2 ,Eden : from : to = 8 : 1 : 1
  • JDK1.8中移除了永久代,替换为元空间区域(Metaspace),因为永久代进场不够用导致内存泄漏(java.lang.OutOfMemoryError: PermGen),元空间的本质和永久代类似,都是对JVM规范中方法区的实现。不过元空间与永久代之间最大的区别在于:元空间并不在虚拟机中,而是使用本地内存。,理论上取决于32位/64位系统可虚拟的内存大小
    在这里插入图片描述

区域特征

  • Young区: 几乎是所有Java对象产生的地方,对于Eden区而言,大部分的对象都不是长期存活的,Young区是触发垃圾回收最频繁的地区,Young区又进一步分为Eden区和两个Survior(From/To)区
  • Eden区: Java新生成的对象现在Eden区分配,当Eden区没有足够的空间进行分配时,虚拟机会触发一次Minor GC
  • Survior区(From/To): 一个 Survior区和Eden区用于创建对象,一个Survior用于存储Minor GC之后还存活的对象
  • Old 区: 多次GC回收之后的对象存储区域
  • Metaspace: 元空间使用的是本地内存,存储的是class的信息、常量、静态变量等数据

垃圾回收方式

堆内存是GC收集垃圾的主要区域,GC方式分为两种:Minor GC、Full GC

Minor GC

  • Minor GC 是发生在新生代中的垃圾收集动作,所采用的是复制算法。
  • JVM每次在堆内存中创建对象时,都是先使用Eden区和其中的一个Survior区,当Minor GC时,将Eden区和Survior区还存活的对象复制到另一块Survior区,再清理掉使用过的Eden区和Survior区,并且将这些对象的年龄设置为1,以后对象在 Survivor 区每熬过一次 Minor GC,就将对象的年龄 + 1,当对象的年龄达到某个值时 ( 默认是 15 岁,可以通过参数 -XX:MaxTenuringThreshold 来设定 ),这些对象就会成为老年代。
  • 当分配一块连续较大的内存空间时,Minor GC之后会直接进入到年老代(字符串、数组)

Full GC

  • Full GC 垃圾回收在Metaspace中触发,所采用的是标记清除算法。
  • Full GC 耗时比 Minor GC大的多,所以 Full GC得频率比 Minor GC低得多
  • Full GC是针对整个堆来说的,一般都伴随着 Minor GC
  • 如果启动项配置了 -XX:+UseConcMarkSwapGC,虚拟机会启用CMS回收算法,每隔指定时间(默认2S)检查年老代是否要启用CMS回收
  • Full GC的触发条件
    1. System.gc()方法的调用
    2. 堆空间不足,如果FullGC之后还是 不足,会抛java.lang.OutOfMemoryError: Java heap space
    3. Permanet Generation空间不足,Permanet Generation空间存放的为一些class的信息、常量、静态变量等数据,当系统中要加载的类、反射的类和调用的方法较多时,回收之后还沾满,会抛java.lang.OutOfMemoryError: PermGen space
    4. 堆中连续分配很大的空间,比如很大的数组

JVM垃圾回收算法

  • 判断对象是否可回收的算法:引用计数法、根搜索法
  • 垃圾回收算法可分为:标记清除法、复制法、标记整理法、分代回收法
    在这里插入图片描述

对象可回收算法

  • 引用计数法: 每个设置一个计数器,当引用这个对象时,计数器+1,引用失效时-1,计数器为0时,引用失效,判定为可回收对象,这样不能解决循环引用问题(A引用B,B引用A),该算法已废弃
  • 根搜索方法:GCRoots作为根节点,向下搜索,形成引用链,那些不在引用链上的对象,是可回收的对象,GCRoots可以为:
  1. 虚拟机栈(栈帧中的本地变量表)中的引用的对象
  2. 方法区域中的类静态属性引用的对象
  3. 方法区域中常量引用的对象
  4. 本地方法栈中JNI(Native方法)的引用的对象

垃圾回收算法

标记-清除算法
  • 标记-清除算法分为标记和清除两个阶段。在标记阶段,通过GCRoots标记从根节点开始所有可达的对象,在清除阶段清除未被标记的(未被引用)的对象
  • 缺点:容易产生空间碎片,可能会导致没有可用的连续的较大内存
标记整理算法
  • 标记整理算法是 在对象标记完的基础上,将未引用的对象移动到内存另一端,然后清理标记对象边界外的对象,这样避免了内存碎片的产生
  • 缺点:标记-整理算法是在标记-清除算法的基础上,又进行了对象的移动,效率更低
复制算法
  • 准备内存大小相等的两块空间,每次只使用一份 空间,当内存满了之后,从根节点扫描对象,把所有存活的 对象复制到另一份空间,原来的空间全部回收掉
  • 缺点:浪费 一半的空间,存活对象多时需要频繁的复制
分代收集算法
  • 分代收集算法是目前大部分JVM的垃圾收集器采用的算法。
  • 它的核心思想是根据对象存活的生命周期将内存划分为新生代和年老代等几个区域,根据不同的区域特征采用不同的垃圾回收算法
  • 对于年轻代:对象生命周期短 ,需要频繁快速的收集,主要采用复制算法
  • 对于年老代:年老代是经过多次回收之后还存活的对象,因此对象生命周期长,回收频率低,采用标记整理算法
  • 对于永久代:永久代并非不进行回收,Permanet Generation空间存放的为一些class的信息、常量、静态变量等数据,回收的主要是废弃的常量和class

参考

https://blog.youkuaiyun.com/xiangzhihong8/article/details/70306094
https://www.jianshu.com/p/114bf4d9e59e
https://www.cnblogs.com/dennyzhangdd/p/6770188.html
https://juejin.im/post/5b85ea54e51d4538dd08f601
https://www.cnblogs.com/aspirant/p/8662690.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值