解析Java内存分配和回收策略以及MinorGC、MajorGC、FullGC
作者:没头脑遇到不高兴 发布时间:2023-02-06 08:22:19
对象内存分配与回收策略
对象的内存分配,往大方向讲,就是在堆上分配〔但也可能经过JIT编译后被拆散为标量类型并间接地栈上分配),对象主要分配在新生代的Eden区上,如果启动了本地线程分配缓冲,将按线程优先在TLAB上分配。少数情况下也可能会直接分配在老年代中。
对象优先分配在Eden区,当Eden区可用空间不够时会进行MinorGC
大对象直接进入老年代:大对象即需要大量连续内存空间的对象(例如很长的字符串及数组)。虚拟机提供了一个-XX:PretenureSizeThreshoId参数,令大于这个设置值的对象直接在老年代分配,这样做的目的是避免在Eden区及两个区之间发生大量的内存复制。注意PretenureSizeThreshoId参数只对Serial和ParNew两款收集器有效。
长期存活的对象将进入老年代:虚拟机给每个对象定义了一个对象年龄(Age)计数器(存在于对象头中)。如果对象在Eden出生并经过第一次MinorGC后仍然存活,并且能被Survivor容纳的话,将被移动到Survwor空间中,并且对象年龄设为1。对象在Survivor区中每“熬过”一次MinorGC,年龄就增加1岁,当它的年龄增加到一定程度(默认为15岁),就将会被晋升到老年代中。对象晋升老年代的年龄阈值,可以通过参数-XX:MaxTenuringThreshoId设置。
动态年龄判断:为了能更好地适应不同程序的内存状况,虚拟机并不是永远地要求对象的年龄必须达到了MaxTenuringThreshold才能晋升老年代,如果在Survivor空间中相同年龄所有对象大小的总和大于Survivor空间的一半,年龄大于或等于该年龄的对象就可以直接进人老年代,无须等到MaxTenuringThreshoId中要求的年龄。
空间分配担保:在发生Minor GC之前,虚拟机会先检查Survivor空间是否够用,如果够用则直接进行Minor GC。否则进行检查老年代最大连续可用空间是否大于新生代的总和,假如大于,那么这个时候发生Minor GC是安全的。假如不大于,那么需要判断HandlePromotionFailure设置是否允许担保失败。假如允许,则继续判定老年代最大可用的连续空间是否大于平均晋升到老年代对象的平均值,如果大于,这个时候可以发生Minor GC ,如果小于或者设置HandlePromotionFailure不允许担保失败,则需要做一次Full GC。通常会把HandlePromotionFailure开关打开,以减少Full GC。
对象何时进入新生代、老年代
新分配的对象一般是直接进入新生代的。但是如果出现以下的情况,会让对象进入老年代。
1.新分配的对象占用空间大于-XX:PretenureSizeThreshold时直接分配到老年代
2.MinorGC的时候,Survivor中的内存不足了,允许分配担保时会进入老年代。
3.MinorGC的时候,对象的年龄大于-XX:MaxTenuringThreshold(默认为15)时,进入老年代。对象年龄存在于对象头中,占4bit。
4.当进行MinorGC的时候,如果在Survivor空间中相同年龄所有对象大小的总和大于Survivor空间的一半,年龄大于或等于该年龄的对象就可以直接进人老年代。
三种GC介绍
MinorGC
从年轻代空间(包括 Eden 和 Survivor 区域)回收内存被称为 Minor GC,也叫Young GC。因为Java对象大多具备朝生夕死的特征,所以MinorGC非常频繁,一般回收速度也比较快。一般采用复制算法。
Minor GC触发条件
Eden区域满了
新生对象需要分配到新生代的Eden,当Eden区的内存不够时需要进行MinorGC
Major GC/Full GC:
MajorGC:是清理老年代,Major GC发生过程常常伴随一次Minor
FullGC:Full GC可以看做是Major GC+Minor GC共同进行的一整个过程,是清理整个堆空间(包括年轻代和老年代,这里不包含永久代,因为永久代在JDK7之前包含方法区,是一块与堆分离的区域;JDK7将静态变量从永久代移到堆中;JDK8则完全取消永久代,方法区存在元空间MetaSpace中,虽然与堆共享一块内存,逻辑上可以认为在堆中,但仍然与堆不相连)。Full GC的速度一般会比 Minor GC慢10倍以上。一般用的是标记整理和标记清除算法
Full GC触发条件
上面Minor GC时介绍中Survivor空间不足时,判断是否允许担保失败,如果不允许则进行Full GC。如果允许,并且每次晋升到老年代的对象平均大小>老年代最大可用连续内存空间,也会进行Full GC。
MinorGC后存活的对象超过了老年代剩余空间
方法区内存不足时
System.gc(),可用通过-XX:+ DisableExplicitGC来禁止调用System.gc
CMS GC异常,CMS运行期间预留的内存无法满足程序需要,就会出现一次“Concurrent Mode Failure”失败,会触发Full GC
图示GC过程
1:初始阶段,对象分配在Eden区(大对象直接进入老年代,通过-XX:PretenureSizeThreshold配置),此时S0和S1是空的(圆圈中的数字代表对象的年龄)
2:当Eden区满了之后,进行MinorGC,经过扫描与标记,不再存活的对象被清除,存活的对象进入Survivor中的S0并且对象年龄+1,此时Eden被清空,S1是空的
3:然后随着对象增多又一次MinorGC后,Eden区和S0区存活的对象进入S1区并且对象年龄+1,Eden和S0区被清空
4:又一次MinorGC后,和上面步骤类似,Eden区和S1区存活的对象进入S0区并且对象年龄+1,Eden和S1区被清空
5:对象每熬过一次MinorGC其年龄就会加1,达到年龄阈值(可通过参数-XX:MaxTenuringThreshold配置)的年轻代对象会晋升到老年代,随着进入老年代的对象越来越多,当老年代内存不够用时会发送MajorGC。
来源:https://blog.csdn.net/u012988901/article/details/100630491
猜你喜欢
- 默认情况下,如果应用以 Android Q 为目标平台,则在访问外部存储设备中的文件时会进入过滤视图。应用可以使用 Context.getE
- package other;import java.security.MessageDigest;import java.security.
- @Order控制配置类/AOP/方法/字段的加载顺序1.AOP加载顺序 @Component &nbs
- 前2天有读者问到是否有带分页功能的表格控件,今天分页功能的表格控件详细解析。PaginatedDataTablePaginatedDataT
- Java Collection API提供了一些列的类和接口来帮助我们存储和管理对象集合。其实Java中的集合工作起来像是一个数组,不过集合
- trim中prefix与suffix等标签用法1.prefix 前缀增加的内容2.suffix 后缀增加的内容3.prefixOverrid
- 一、API简介Thread.sleep()是Thread类的一个静态方法,使当前线程休眠,进入阻塞状态(暂停执行),如果线程在睡眠状态被中断
- 本文实例为大家分享了Java实现简单幸运抽奖的具体代码,供大家参考,具体内容如下代码模块:User类:package test1;publi
- JAVA中Integer类下的常用方法有哪些?1.进制转换 n进制转10进制 字符串结果Integer.parseInt(String s,
- 访问控制:private 私有的protected 受保护的public 公共的类、方法和变量修饰符abstract 声明抽象class 类
- 用java实现的登录与注册页面,实现了客户端(浏览器)到服务器(Tomcat)再到后端(servlet程序)数据的交互。这里在注册页面加入了
- 在 Flutter 中使用图片是最基础能力之一。作为春节开工后的第一篇文章,17 做了精心准备,满满的都是干货!本文介绍如何在 Flutte
- 前言MyBatis-Plus 是基于 MyBatis 进行封装的一套优秀的持久层框架,它提供了丰富的便捷操作方法和强大的代码生成器,大大简化
- 本文实例总结了java判断字符串是否为数字的方法。分享给大家供大家参考,具体如下:方法一:用JAVA自带的函数public static b
- 1.内部类概念及分类将一个类定义在另一个类的内部或者接口内部或者方法体内部,这个类就被称为内部类,我们不妨将内部类所在的类称为外围类,除了定
- 在基于UI元素的自动化测试中, 无论是桌面的UI自动化测试,还是Web的UI自动化测试. 首先我们需要查找和识别UI
- 最近一个项目中,需要用到Java的websocket新特性,于是就学了一下,感觉这技术还挺好玩的,瞬间知道网页上面的那些在线客服是怎么做的了
- strftime函数主要用于时间格式化,它的函数原型如下:size_t __cdecl strftime(char * __restrict
- 在编写类的时候可以使用两种方式定义类:public class定义类:class定义类:如果一个类声明的时候使用了public class进
- 前言最近在项目中使用到定时任务,之前一直都是使用Quartz 来实现,最近看Spring 基础发现其实Spring 提供 Spring Sc