首页 > 运维 > linux运维 > 正文

深入理解JVM内存分配策略

蓮花仙者
发布: 2025-07-21 12:28:27
原创
321人浏览过

大家好,我们又见面了,我是你们的朋友全栈君。

深入探讨JVM内存分配策略:三大原则与担保机制JVM的内存分配机制包括三大原则和担保机制,具体如下:

首先,对象优先分配到Eden区。其次,大对象直接进入老年代。第三,长期存活的对象会被分配到老年代。最后,空间分配担保也是一个重要的机制。

对象优先在Eden区分配要如何验证这一原则呢?我们可以通过以下实验进行验证。

首先打印内存分配信息,代码如下所示:

public class A {    
    public static void main(String[] args) {        
        byte[] b1 = new byte[4*1024*1024];    
    }
}
登录后复制

代码非常简单,创建了一个大小为4MB的Byte数组。我们在运行时添加虚拟机参数来打印垃圾回收信息。

-verbose:gc -XX:+PrintGCDetails
登录后复制

运行后,结果如下所示。

我们手动指定收集器,可以看到新生代使用的是Parallel Scavenge收集器。实际上,我们可以通过指定虚拟机参数来选择垃圾收集器,例如:

-verbose:gc -XX:+PrintGCDetails -XX:+UseSerialGC
登录后复制

运行结果如下:

虽然JDK默认的不是Parallel收集器,但JDK会根据各种环境调整使用的垃圾收集器。

要查看环境,可以使用以下代码:

java -version
登录后复制

深入理解JVM内存分配策略 因此,JDK根据服务器环境选择了Parallel收集器,而Serial收集器主要用于客户端。

验证Eden区分配我们观察到当前Eden区域为34432K,占用19%。如果我们将分配大小扩大10倍,Eden区是否还能容纳呢?我们来验证一下。

public class A {    
    public static void main(String[] args) {        
        byte[] b1 = new byte[40*1024*1024];    
    }
}
登录后复制

运行结果如下:

因此,我们适当缩小每次分配的大小。我们限制Eden区域的大小,参数如下:

-verbose:gc -XX:+PrintGCDetails -XX:+UseSerialGC -Xms20M -Xmx20M -Xmn10M -XX:SurvivorRatio=8
登录后复制

这里我们将内存大小限制为20M,Eden大小为8M。

然后我们运行以下代码:

public class A {    
    public static void main(String[] args) {        
        byte[] b1 = new byte[2*1024*1024];        
        byte[] b2 = new byte[2*1024*1024];        
        byte[] b3 = new byte[2*1024*1024];        
        byte[] b4 = new byte[4*1024*1024];        
        System.gc();    
    }
}
登录后复制

运行结果如下:

原先的b1、b2、b3总共6M,被分配到了老年代。

原先的Eden区域如下图所示,在分配完b1、b2、b3后如下图所示。

深入理解JVM内存分配策略 此时我们发现已经无法继续分配了。

查看日志时,我们发现发生了两次GC。

[DefNew: 7129K->520K(9216K), 0.0053010 secs] 7129K->6664K(19456K), 0.0053739 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 
登录后复制

中我们会看到,刚分配的对象并没有被回收。

存了个图
存了个图

视频图片解析/字幕/剪辑,视频高清保存/图片源图提取

存了个图 17
查看详情 存了个图

上面的GC是针对新生代的,而下面的FullGC是针对老年代的。

如果我们此时要再分配4MB的内存,虚拟机会将原先的Eden区域放到可放的地方,即老年代。

因此会发生这种情况。

深入理解JVM内存分配策略 这就是整个过程,验证了对象优先在Eden区域分配。


大对象直接进入老年代指定大对象的参数如下:

-XX:PretenureSizeThreshold
登录后复制

测试代码如下:

-verbose:gc -XX:+PrintGCDetails -XX:+UseSerialGC -Xms20M -Xmx20M -Xmn10M -XX:SurvivorRatio=8
登录后复制
public class A {    
    private static int M = 1024*1024;    
    public static void main(String[] args) {        
        byte[] b1 = new byte[8*M];    
    }
}
登录后复制

运行结果如下:

我们可以看到,结果直接将8MB放到了老年代。而当我们将大小改为7MB时,

深入理解JVM内存分配策略 我们发现7MB全部被放到了Eden区。如果我们指定了参数,会发现结果变了。

参数如下所示:

-verbose:gc -XX:+PrintGCDetails -XX:+UseSerialGC -Xms20M -Xmx20M -Xmn10M -XX:SurvivorRatio=8 -XX:PretenureSizeThreshold=6M
登录后复制

运行结果如下:

深入理解JVM内存分配策略 我们会发现7MB进入了老年代。

长期存活对象进入老年代---

参数如下:

-XX:MaxTenuringThreshold
登录后复制

每次进行回收时,如果对象没有被回收,那么对象的年龄会加1。

当对象的年龄达到阈值时,它会进入老年代。

具体测试与上述类似,这里就不再赘述了。


空间分配担保参数如下:

-XX:+HandlePromotionFailure
登录后复制

步骤如下:

首先,JVM会评估是否有足够的空间,然后才能进行分配。如果有能力放入,那么这个参数是‘+’号,表示开启了内存担保,否则是‘-’号,表示未开启。


总结:JVM的内存分配策略并不特别复杂,只要一步一步跟随虚拟机的操作,就可以理解其内存分配机制。

发布者:全栈程序员栈长,转载请注明出处:https://www.php.cn/link/ab4981fb59db07f87db4b1a7a2e9efcf

以上就是深入理解JVM内存分配策略的详细内容,更多请关注php中文网其它相关文章!

相关标签:
最佳 Windows 性能的顶级免费优化软件
最佳 Windows 性能的顶级免费优化软件

每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号