千家信息网

Java虚拟机中内存分配与回收策略的示例分析

发表于:2025-11-13 作者:千家信息网编辑
千家信息网最后更新 2025年11月13日,小编给大家分享一下Java虚拟机中内存分配与回收策略的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!内存分配与回收
千家信息网最后更新 2025年11月13日Java虚拟机中内存分配与回收策略的示例分析

小编给大家分享一下Java虚拟机中内存分配与回收策略的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!

内存分配与回收策略

Java技术体系的自动内存管理,最根本的目标是自动化地解决两个问题:自动给对象分配内存以及自动回收分配给对象的内存。

1. 综述

对象的内存分配,从概念上讲,应该都是在堆上分配(而实际上也有可能经过即时编译后被拆散为标量类型并间接地在栈上分配)。在经典分代的设计下,新生对象通常会分配在新生代中,少数情况下(例如对象大小超过一定阈值)也可能会直接分配在老年代。对象分配的规则并不是固定的,《Java虚拟机规范》并未规定新对象的创建和存储细节,这取决于虚拟机当前使用的是哪一种垃圾收集器,以及虚拟机中与内存相关的参数的设定。

(1)、对象优先在Eden分配

大多数情况下,对象在新生代Eden区中分配。当Eden区没有足够空间进行分配时,虚拟机将发起一次Minor GC。

1. Eden区有足够空间的情形

虚拟机参数

-verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8

参数说明

尝试分配三个2MB大小和一个4MB大小的对象,在运行时通过-Xms20M、-Xmx20M、-Xmn10M这三个参数限制了Java堆大小为20MB,不可扩展,其中10MB分配给新生代,剩下的10MB分配给老年代。-XX:Survivor-Ratio=8决定了新生代中Eden区与一个Survivor区的空间比例是8∶1。

package com.xiao.test.Test;public class test {    private static final int _1MB = 1024 * 1024;    public static void main(String[] args) {        byte[] byte1,byte2,byte3;        byte1 = new byte[2 * _1MB];        byte2 = new byte[2 * _1MB];        byte3 = new byte[2 * _1MB];       }}

2. Eden区没有足够空间的情形

虚拟机参数相同

package com.xiao.test.Test;public class test {    private static final int _1MB = 1024 * 1024;    public static void main(String[] args) {        byte[] byte1,byte2,byte3,byte4;        byte1 = new byte[2 * _1MB];        byte2 = new byte[2 * _1MB];        byte3 = new byte[2 * _1MB];        byte4 = new byte[3 * _1MB];    }}

显然进行了Minor GC

(2)、大对象直接进入老年代

1. 什么是大对象?

大对象就是指需要大量连续内存空间的Java对象,最典型的大对象便是那种很长的字符串,或者元素数量很庞大的数组。

2. Java虚拟机中要避免大对象的原因

在分配空间时,它容易导致内存明明还有不少空间时就提前触发垃圾收集,以获取足够的连续空间才能安置好它们。而当复制对象时,大对象就意味着高额的内存复制开销。

3. 大对象直接进入老年代的好处

避免在Eden区及两个Survivor区之间来回复制,产生大量的内存复制操作(HotSpot虚拟机提供了-XX:PretenureSizeThreshold参数,指定大于该设置值的对象直接在老年代分配)。

(3)、长期存活的对象将进入老年代

1. 虚拟机是怎样判断对象是否是长期存活?

内存回收时就必须能决策哪些存活对象应当放在新生代,哪些存活对象放在老年代中。为做到这点,虚拟机给每个对象定义了一个对象年龄(Age)计数器,存储在对象头中。

2. 对象年龄增加及晋升至老年代过程

对象通常在Eden区里诞生,如果经过第一次Minor GC后仍然存活,并且能被Survivor容纳的话,该对象会被移动到Survivor空间中,并且将其对象年龄设为1岁。对象在Survivor区中每熬过一次Minor GC,年龄就增加1岁,当它的年龄增加到一定程度(默认为15),就会被晋升到老年代中。对象晋升老年代的年龄阈值,可以通过参数-XX:MaxTenuringThreshold设置。

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

我们都知道新生代的垃圾收集算法算法是标记-复制算法,如果长期存活的对象仍然存放在新生代的话,那么就会带来复制的开销增大的问题。所以我们将大于某一年龄阈值的对象放入老年代,这样可以减轻新生代垃圾回收时的压力。

(4)、动态对象年龄判定

为了能更好地适应不同程序的内存状况,HotSpot虚拟机并不是永远要求对象的年龄必须达到-XX:MaxTenuringThreshold才能晋升老年代,如果在Survivor空间中相同年龄所有对象大小的总和大于Survivor空间的一半,年龄大于或等于该年龄的对象就可以直接进入老年代,无须等到-XX:MaxTenuringThreshold中要求的年龄。

(5)、空间分配担保

1. 空间分配担保的内容

在发生Minor GC之前,虚拟机必须先检查老年代最大可用的连续空间是否大于新生代所有对象总空间,如果这个条件成立,那这一次Minor GC可以确保是安全的。如果不成立,则虚拟机会先查看-XX:HandlePromotionFailure参数的设置值是否允许担保失败;如果允许,那会继续检查老年代最大可用的连续空间是否大于历次晋升到老年代对象的平均大小,如果大于,将尝试进行一次Minor GC,尽管这次Minor GC是有风险的;如果小于,或者 -XX:HandlePromotionFailure设置不允许冒险,那这时就要改为进行一次Full GC。

2. "冒险"是冒了什么风险

前面提到过,新生代使用复制收集算法,但为了内存利用率,只使用其中一个Survivor空间来作为轮换备份,因此当出现大量对象在Minor GC后仍然存活的情况--最极端的情况就是内存回收后新生代中所有对象都存活,需要老年代进行分配担保,把Survivor无法容纳的对象直接送入老年代,这与生活中贷款担保类似。老年代要进行这样的担保,前提是老年代本身还有容纳这些对象的剩余空间,但一共有多少对象会在这次回收中活下来在实际完成内存回收之前是无法明确知道的,所以只能取之前每一次回收晋升到老年代对象容量的平均大小作为经验值,与老年代的剩余空间进行比较,决定是否进行Full GC来让老年代腾出更多空间。

3. 那我们需要把担保打开吗?

取历史平均值来比较其实仍然是一种赌概率的解决办法,也就是说假如某次Minor GC存活后的对象突增,远远高于历史平均值的话,依然会导致担保失败。如果出现了担保失败,那就只好老老实实地重新发起一次Full GC,这样停顿时间就很长了。虽然担保失败时绕的圈子是最大的,但通常情况下都还是会将-XX:HandlePromotionFailure开关打开,避免Full GC过于频繁。

以上是"Java虚拟机中内存分配与回收策略的示例分析"这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注行业资讯频道!

对象 年代 分配 空间 内存 年龄 新生 新生代 担保 参数 大小 晋升 情况 垃圾 算法 策略 最大 内容 篇文章 阈值 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 别来无恙吉他谱软件开发 山东质量好的浪潮服务器 杭州小碟网络技术有限公司 ssh发送给多台服务器指令 服务器安全狗设置备份 数据防泄密软件开发公司 光网络技术工程师薪资待遇 doris数据库简介 游戏服务器和手机哪个好 张掖网络安全局 32寸显示器适合软件开发吗 网站服务器集群的安全威胁 计算机软件开发和嵌入式开发 斐讯k2网络安全吗 dw服务器模型 龙岗区网络技术转移五星服务 软件开发去中国银行还是农商行 武汉烽火通信软件开发加班 服务器温度高 上海机械网络技术试验设备 网络安全证书需要考什么 莱瑞软件开发有限公司 大学生网络安全宣传视频素材 数据库远程方关闭传输流 小米路由器开放网络安全吗 平江县公安局网络安全大队 黄浦区信息软件开发电话多少 淘宝助理数据库失败 戴尔服务器指示灯橙色 软件开发去中国银行还是农商行
0