Java堆内存分配与回收策略

news/2024/9/17 16:45:04

java主要在堆上分配内存,而Java堆又分为新生代(YoungGen)和老年代(OldGen)两个部分,新生代又再分为Eden区和Survivor区两部分,本文根据java堆的划分,描述hotspot的内存分配策略。

image

GC垃圾收集分类

  • Minor GC: 发生在新生代中的垃圾收集,采用复制算法。
  • Major GC/Full GC: 发生在老年代的垃圾收集动作,所采用的是标记-清除或者标记-整理算法。

Eden区和Survivor区

对于采用复制算法的虚拟机,新生代通常有一个Eden区和两个Survivor区。
对象优先在Eden区分配,当Eden区没有足够的空间进行分配时,虚拟机讲发起一次Minor GC,Eden中存活的对象将被移动到第一块Survivor区S1,Eden被清空。
当Eden区再次填满,再次触发Minor GC,Eden区和S1中的存活对象被复制送入第二块Survivor区S2中,S1和Eden被清空,下一轮交换S1和S2的角色。
使用两个Survivor区能够简化复制算法的过程,并且避免复制过程中内存碎片的产生。

image

当对象的复制次数达到-XX:MaxTenuringThreshold设置的值(默认-XX:MaxTenuringThreshold=15)时,将被移至老年代。

实验

/*** VM Options:* -Xmx20M 堆最大20M* -Xms20M 堆最小20M* -Xmn10M 新生代为10M* -XX:SurvivorRatio=8 Eden区和Survivor区的比值为8:1* -XX:+PrintGCDetails 输出回收日志及退出时内存各区域情况*/
private static final int _1MB = 1024 * 1024;
public static void testAllocation(){byte[] allocation1,allocation2,allocation3,allocation4;allocation1 = new byte[2 * _1MB];allocation2 = new byte[2 * _1MB];allocation3 = new byte[2 * _1MB];allocation4 = new byte[4 * _1MB];
}

结果:

 PSYoungGen      total 9216K, used 7479K [0x00000007bf600000, 0x00000007c0000000, 0x00000007c0000000)eden space 8192K, 91% used [0x00000007bf600000,0x00000007bfd4df10,0x00000007bfe00000)from space 1024K, 0% used [0x00000007bff00000,0x00000007bff00000,0x00000007c0000000)to   space 1024K, 0% used [0x00000007bfe00000,0x00000007bfe00000,0x00000007bff00000)ParOldGen       total 10240K, used 4096K [0x00000007bec00000, 0x00000007bf600000, 0x00000007bf600000)object space 10240K, 40% used [0x00000007bec00000,0x00000007bf000010,0x00000007bf600000)Metaspace       used 2692K, capacity 4486K, committed 4864K, reserved 1056768Kclass space    used 288K, capacity 386K, committed 512K, reserved 1048576K

在退出时各个区域结果如上, PSYoungGen的PS指的是Parallel Scavenge垃圾回收器,ParOldGen中的Par指的是Parallel Old垃圾回收器。
设置中堆为10M,新生代为10M,因此老年代为10M。设置SurvivorRatio为8:1,因此Eden区大小为8M,Survivor区大小为1M。因为Survivor区同一时刻只有一个能用于分配,因此PSYoungGen区域总可用大小为9M。
在allocation4进行分配时,新生代eden区已经用了6M,只剩2M,无法进行分配,触发MinorGC。新生代中3个2M大小的对象全部无法放入1M的Survivor区中,所以只能通过分配担保机制将两个2M的对象放入老年代中,再将allocation4的4M对象放入Eden区中。
最终Eden区分配6M,survivor区中没有对象,老年代分配4M。

大对象直接进入老年代

大对象是指需要大量连续内存空间的Java对象。为了避免在Eden区及两个Survivor区之间发生大量的内存复制,虚拟机提供了-XX:PretenureSizeThreshold参数。大于该参数设置值的对象将直接分配在老年代。

长期存活对象直接进入老年代

虚拟机给每个对象定义了一个对象年龄计数器,对象每经过一个MinorGC仍然存活,则年龄加一,当年龄增加到超过-XX:MaxTenuringThreshold设置的值(默认为16)时,将被移至老年代。

空间分配担保

如文章开头的例子中,当出现大量对象在MinorGC后仍然存活的情况,Survivor区无法容纳多余的对象,此时,需要老年代进行分配担保,把Survivor无法容纳的对象直接进入老年代。JDk 6 Update 24之后,担保的规则是,只要老年代的连续空间大于新生代对象总大小或者历次晋升的平均大小就会进行MinorGC,否则将进行Full GC。

参数设置小结

参数描述
-Xms20M堆最小值
-Xmx20M堆最大值
-Xmn10M新生代大小
-XX:SurvivorRatio=8Eden区比Survivor区的大小
-XX:+PrintGCDetails输出回收日志和退出时各内存区域情况
-XX:PretenureSizeThreshold=10M大于该参数设置值的对象直接分配在老年代
-XX:MaxTenuringThreshold=15新生代对象年龄增加到超过该值时,将被移至老年代

http://lihuaxi.xjx100.cn/news/236917.html

相关文章

“区块链”究竟是什么

链客,专为开发者而生,有问必答! 此文章来自区块链技术社区,未经允许拒绝转载。 什么是区块链? 说到区块链,就不得不说比特币。   2008年底,比特币之父中本聪发表了一个关于他研究的电子现金…

sass的继承,混合宏,占位符的用法总结

SCSS中混合宏使用 mixin mt($var){ margin-top: $var; }.block { include mt(5px);span { display:block; include mt(5px); } }extend如何工作 .icon {transition: background-color ease .2s;margin: 0 .5em;}.error-icon {extend .icon;/*错误图标指定的样式... */}.info-i…

首例利用智能路由网关犯罪嫌疑人被捕:罪名流量劫持

首例利用智能路由网关犯罪嫌疑人被捕:罪名流量劫持 https://tech.sina.cn/digi/nb/2018-05-15/detail-ihapkuvm0295695.d.html 上海市徐汇区人民检察院依法以破坏计算机信息系统罪对全市首例利用智能路由网关设备进行流量劫持的犯罪嫌疑人章某批准逮捕。 经查,2018年…

区块链技术未来可能用于哪些方面?

链客,专为开发者而生,有问必答! 此文章来自区块链技术社区,未经允许拒绝转载。 当世界上从100比特币购买25美分的比萨饼,到一比特币兑换4800人民币的天价,在这风起云涌的纪念,我们见证了一个…

解决bootstrap下的图片自适应问题

.img-responsive {display: block; height: auto; max-width: 100%; }转载于:https://www.cnblogs.com/qjuly/p/9809910.html

区块链技术到底有啥用?

链客,专为开发者而生,有问必答! 此文章来自区块链技术社区,未经允许拒绝转载。 前言:关于区块链适合做什么和不适合做什么?一直都有争议。那么,通过什么方式来辨别呢?本文用详细的…

Moya基本用法

Moya简介 一句话来讲,Moya是对Alamofire的封装,让开发人员更加优雅的使用Alamofire。 基本用法 定义接口枚举 public enum HFAPI {case login(String, String, String) //登录接口case smscode(String) //登录,发送验证码 } 复制代码 拓展…

正确生成浮点型的方法,解决sqlachemy Float浮点型的坑,生成float类型时,长度和精度均为0,导致查询不到结果!...

问题描述 在使用flask_sqlachemy时,给price字段选择了Float类型,数据库用的mysql,生成数据库表后,发现 from sqlalchemy import Float,Column price Column(Float,default0.00) 虽然能存储float类型,结果如下 但是查询…