首页 > 系统相关 >Java内存分配与回收策略

Java内存分配与回收策略

时间:2024-01-24 23:11:55浏览次数:18  
标签:Full Java 对象 虚拟机 回收 GC 内存 年代 Minor

HotSpot 虚拟机 GC 分类

针对 HotSpot 虚拟机的实现,GC 可以分为 2 大类:

  • 部分收集(Partial GC)

    • 新生代收集(Minor GC / Young GC):回收新生代,因为新生代对象存活时间很短,因此 Minor GC 会频繁执行,执行的速度一般也会比较快。
    • 老年代收集(Major GC / Old GC):只对老年代进行垃圾收集。需要注意的是 Major GC 在有的语境中也用于指代 Full GC。只有 CMS 的并发清除存在这个模式
    • 混合收集(Mixed GC):对整个新生代和部分老年代进行垃圾收集。只有 G1 存在这个模式
  • 整堆收集(Full GC)

    收集整个 Java 堆,包括新生代、老年代和永久代(如果存在的话)。老年代对象其存活时间长,因此 Full GC 很少执行,执行速度会比 Minor GC 慢很多。

内存分配策略

1. 对象优先在 Eden 分配

大多数情况下,对象在新生代 Eden 上分配,当 Eden 空间不够时,发起 Minor GC。

2. 大对象直接进入老年代

大对象是指需要连续内存空间的对象,最典型的大对象是那种很长的字符串以及数组。

经常出现大对象会提前触发垃圾收集以获取足够的连续空间分配给大对象。

-XX:PretenureSizeThreshold,大于此值的对象直接在老年代分配,避免在 Eden 和 Survivor 之间的大量内存复制。

3. 长期存活的对象进入老年代

为对象定义年龄计数器,对象在 Eden 出生并经过 Minor GC 依然存活,将移动到 Survivor 中,年龄就增加 1 岁,增加到一定年龄则移动到老年代中。

-XX:MaxTenuringThreshold 用来定义年龄的阈值,默认值为15。

4. 动态对象年龄判定

虚拟机并不是永远要求对象的年龄必须达到 MaxTenuringThreshold 才能晋升老年代,如果在 Survivor 中相同年龄所有对象大小的总和大于 Survivor 空间的一半,则年龄大于或等于该年龄的对象可以直接进入老年代,无需等到 MaxTenuringThreshold 中要求的年龄。

5. 空间分配担保

在发生 Minor GC 之前,虚拟机先检查老年代最大可用的连续空间是否大于新生代所有对象总空间,如果条件成立的话,那么 Minor GC 可以确认是安全的。

如果不成立的话虚拟机会查看 HandlePromotionFailure 的值是否允许担保失败,如果允许那么就会继续检查老年代最大可用的连续空间是否大于历次晋升到老年代对象的平均大小,如果大于,将尝试着进行一次 Minor GC;如果小于,或者 HandlePromotionFailure 的值不允许冒险,那么就要进行一次 Full GC。

Full GC 的触发条件

对于 Minor GC,其触发条件非常简单,当 Eden 空间满时,就将触发一次 Minor GC。而 Full GC 则相对复杂,有以下条件:

1. 调用 System.gc()

只是建议虚拟机执行 Full GC,但是虚拟机不一定真正去执行。不建议使用这种方式,而是让虚拟机管理内存。

2. 老年代空间不足

老年代空间不足的常见场景为前文所讲的大对象直接进入老年代、长期存活的对象进入老年代等。

为了避免以上原因引起的 Full GC,应当尽量不要创建过大的对象以及数组。除此之外,可以通过 -Xmn 虚拟机参数调大新生代的大小,让对象尽量在新生代被回收掉,不进入老年代。还可以通过 -XX:MaxTenuringThreshold 调大对象进入老年代的年龄,让对象在新生代多存活一段时间。

3. 空间分配担保失败

使用复制算法的 Minor GC 需要老年代的内存空间作担保,如果担保失败会执行一次 Full GC。具体内容请参考上面的第 5 小节。

4. JDK 1.7 及以前的永久代空间不足

在 JDK 1.7 及以前,HotSpot 虚拟机中的方法区是用永久代实现的,永久代中存放的为一些 Class 的信息、常量、静态变量等数据。

当系统中要加载的类、反射的类和调用的方法较多时,永久代可能会被占满,在未配置为采用 CMS GC 的情况下也会执行 Full GC。如果经过 Full GC 仍然回收不了,那么虚拟机会抛出 java.lang.OutOfMemoryError。

为避免以上原因引起的 Full GC,可采用的方法为增大永久代空间或转为使用 CMS GC。

5. Concurrent Mode Failure

执行 CMS GC 的过程中同时有对象要放入老年代,而此时老年代空间不足(可能是 GC 过程中浮动垃圾过多导致暂时性的空间不足),便会报 Concurrent Mode Failure 错误,并触发 Full GC。

参考:

标签:Full,Java,对象,虚拟机,回收,GC,内存,年代,Minor
From: https://www.cnblogs.com/i9code/p/17986077

相关文章

  • java类文件结构
    类文件概述JVM可以理解的代码就叫做字节码(即扩展名为.class的文件,即类文件),它不面向任何特定的处理器,只面向虚拟机。Java语言通过字节码的方式,在一定程度上解决了传统解释型语言执行效率低的问题,同时又保留了解释型语言可移植的特点。字节码并不针对一种特定的机器,因此Java......
  • java垃圾收集
    垃圾回收的脑图垃圾收集主要是针对堆和方法区进行。程序计数器、虚拟机栈和本地方法栈这三个区域属于线程私有的,只存在于线程的生命周期内,线程结束之后就会消失,因此不需要对这三个区域进行垃圾回收。判断一个对象是否可被回收1.引用计数算法为对象添加一个引用计数器,当对象增......
  • Java学习日记 Day10
    Spring框给架:AOP:AOP切面编程一般可以帮助我们在不修改现有代码的情况下,对程序的功能进行拓展,往往用于实现日志处理,权限控制,性能检测,事务控制等。JDBCtemplate:我们做好配置文件以及加入依赖后可以通过JDBCtemplate技术来简化对数据库的操作。Spring事务:实现方式主要是注......
  • JAVA XStream简单使用
    XStreamxStream=newXStream(newStaxDriver());xStream.addPermission(AnyTypePermission.ANY);//不加后面转实体变异常xStream.processAnnotations(resultDTO.getClass());resultDTO=(ResultDTO)xStream.fromXML(result); 1、实体类设置别名  @XStreamAlias("Ma......
  • JavaScript ES6中 module , import和export
      假如你想直接在html的script里面使用import,你会遇到以下这两个问题:需要给script标签添加type='module'属性会遇到跨域问题,不单独启用一个服务器无法解决如果不启动一个server,访问js用的协议是file,不在浏览器跨域允许的协议中。因此无法做到拿到js文件,......
  • Java基础(一)
    文章目录第一章、java环境搭建1.1、Java介绍1.1.1、Java开发平台1.1.2、Java开发环境搭建1.1.3、Java专业术语1.1.4、第一个Java程序1.1.5、练习1.2、main方法1.3、变量1.3.1、变量介绍1.3.2、练习1.3.3、变量名规范1.3.4、注释1.4、数据类型......
  • 韩顺平java基础-13-常用类
    韩顺平java基础-13-常用类常用类包装类分类装箱和拆箱//自动装箱intn1=100;Integerinteger=intn1;//自动调用Integer.valueOf(n1)的方法//自动拆箱intn2=integer;//自动调用integer.intValue的方法包装类与String转换包装类型--->String类toString()......
  • 最佳实践:如何发现、修复和防止 Node.js 内存泄漏
    这篇文章将介绍什么是内存泄漏以及如何在Node.js应用程序中避免内存泄漏。什么是内存泄漏?在深入研究内存泄漏的细节之前,有必要先了解什么是内存生命周期。为已定义变量分配内存对分配的内存进行读、写等操作。使用后,释放分配的内存内存泄漏是指当程序没有释放它分配的内存时,即生......
  • linux 安装多版本java,并可切换版本
    我多版本切换,省事操作。配置:/etc/profileexportJAVA_HOME=/usr/java/jdk/jdk1.8.0_201exportJRE_HOME=/usr/java/jdk/jdk1.8.0_201/jreexportCLASSPATH=.:$JAVA_HOME/lib:$JRE_HOME/lib:$CLASSPATHexportPATH=$JAVA_HOME/bin:$JRE_HOME/bin:$JAVA_HOME:$PATH#切换1.8......
  • Java抛出异常且没有被捕捉的情况下,后面的代码还能运行吗?
    Java有try-catch-finally的异常处理机制,包括以下几种情况:1、不抛出异常,try里面的代码、finally里面的代码、finally以后的代码都将正常执行,而catch里面的代码不会执行。2、抛出异常且被catch捕获,try里面的代码部分执行,catch里面的代码、finally里面的代码、finally以后的代码都将......