《深入理解java虚拟机》笔记(6)内存分配与回收策略
一、垃圾回收日志说明
[GC[DefNew: 7307K->494K(9216K), 0.0043710 secs] 7307K->6638K(19456K), 0.0044894 secs] [Times: user=0.02 sys=0.00, real=0.01 secs]
1、日志开发的“[GC”说明了这次垃圾回收的停顿类型,如果有FULL,说明这次GC是发生了Stop-The-World的。
2、接下来的“[DefNew”表示GC发生的区域,这里显示的区域名称与使用的GC收集器是密切相关的。例如Serial收集器中的新生代名“Default New Generation”,所以显示的是“[DefNew”。如果是ParNew收集器,显示“[ParNew”。如果是Parallel Scavenge收集器,显示“PSYoungGen”。
3、后面方括号内部的“7307K->494K(9216K)”含义是:GC前该区域已使用容量->GC后该区域已使用容量(该内存区域总容量)。而在方括号之外的“7307K->6638K(19456K)”含义是:GC前Java堆已使用容量->GC后Java堆已使用容量(Java堆总容量)。
4、再往后,“0.0044894 secs”表示该内存区域GC所占用的时间,单位秒。
二、对象优先在Eden分配
对象通常在新生代的Eden区分配,当Eden区没有足够空间时,虚拟机会发起一次Minor GC。与Minor GC对应的还有Major GC、Full GC。
Minor GC:指发生在新生代的垃圾收集动作,非常频繁。速度较快。
Major GC:指发生在老年代的GC,出现Major GC,经常会伴随一次Minor GC,同时Minor GC也会引起Major GC,一般在GC日志中统称为GC,不频繁。
Full GC:指发生在老年代和新生代的GC,速度较慢,需要Stop The World。
测试代码:
/**
* 虚拟机参数为“-verbose:gc -XX:+PrintGCDetails -Xms20M -Xmx20M -Xmn10M -XX:SurvivorRatio=8”,即10M新生代,10M老年代,10M新生代中8M的Eden区,两个Survivor区各1M
* -Xms为堆最小容量,-Xmx为堆最大容量,-Xmn为新生代容量,SurvivorRatio=8为Eden和Survivor(from、to)比例为8:1:1
*/
public class TestAllocation { private static final int _1MB = 1024 * 1024;
public static void test() {
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]; //出现一次minor GC
} public static void main(String[] args) {
test();
}
}
测试结果:
[GC[DefNew: 7307K->494K(9216K), 0.0043710 secs] 7307K->6638K(19456K), 0.0044894 secs] [Times: user=0.02 sys=0.00, real=0.01 secs]
Heap
def new generation total 9216K, used 4920K [0x04800000, 0x05200000, 0x05200000)
eden space 8192K, 54% used [0x04800000, 0x04c52770, 0x05000000)
from space 1024K, 48% used [0x05100000, 0x0517b970, 0x05200000)
to space 1024K, 0% used [0x05000000, 0x05000000, 0x05100000)
tenured generation total 10240K, used 6144K [0x05200000, 0x05c00000, 0x05c00000)
the space 10240K, 60% used [0x05200000, 0x05800030, 0x05800200, 0x05c00000)
compacting perm gen total 12288K, used 1672K [0x05c00000, 0x06800000, 0x09c00000)
the space 12288K, 13% used [0x05c00000, 0x05da22f0, 0x05da2400, 0x06800000)
说明:
GC前新生代占用了7M,然后来了一个4M,Eden和from仅剩下2M不够分配了,触发了一次Minor GC。但是GC后内存仍然不够,因为application1、application2、application3三个引用还存在,另外一块1M的survivor也不够放下这总共6M的三个对象,那么这次Minor GC的效果其实是通过分配担保机制将这6M的内容转入老年代中。然后再来一个4M的,由于此时Minor GC之后新生代只用了494K,够分配了,所以4M顺利进入新生代。
三、大对象直接进入老年代
大对象是指需要大量连续内存空间的Java对象,最典型的大对象是那种很长的字符串以及数组,大对象对虚拟机的分配来说是个坏消息(比遇到大对象更加怀的消息就是遇到一群“朝生夕灭”的短命大对象,写程序时候应避免)。经常出现大对象容易导致内存还有不少空间时就提前触发垃圾收集器回收,以获取足够的连续空间来安置他们。
虚拟机提供了-XX:PretenureSizeThreadshold参数来设置大对象的阀值,超过阀值的对象直接进入老年代。这样做的目的是避免在Eden区及两个Survivor区之间发生大量的内存复制(新生代采用复制算法收集)。
测试代码(超过3M直接分配进老年代):
/**
* -verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8
* -XX:PretenureSizeThreadshold=3145728
*/
public class TestPretenureSizeThreadshold { private static final int _1MB = 1024 * 1024; public static void main(String[] args) {
byte[] application = new byte[4 * _1MB]; }
}
测试结果:
Heap
def new generation total 9216K, used 1327K [0x04600000, 0x05000000, 0x05000000)
eden space 8192K, 16% used [0x04600000, 0x0474bf18, 0x04e00000)
from space 1024K, 0% used [0x04e00000, 0x04e00000, 0x04f00000)
to space 1024K, 0% used [0x04f00000, 0x04f00000, 0x05000000)
tenured generation total 10240K, used 4096K [0x05000000, 0x05a00000, 0x05a00000)
the space 10240K, 40% used [0x05000000, 0x05400010, 0x05400200, 0x05a00000)
compacting perm gen total 12288K, used 1670K [0x05a00000, 0x06600000, 0x09a00000)
the space 12288K, 13% used [0x05a00000, 0x05ba1a50, 0x05ba1c00, 0x06600000)
四、长期存活对象进入老年代
虚拟机给每个对象定义了一个年龄计数器,如果对象在Eden出生并经过第一次Minor GC后仍然存活,并且能够被Survivor容纳,对象年龄就加1。对象在Survivor区每熬过一次Minor GC,年龄就加1。当年龄超过一定阀值(默认为15),则进入老年代中。阀值可通过-XX:MaxTenuringThreshold来设置。
测试代码:
/**
* -verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8
* -XX:MaxTenuringThreshold=1 -XX:+PrintTenuringDistribution
*/
public class TestTenuringThreshold { private static final int _1MB = 1024 * 1024; public static void main(String[] args) {
byte[] allocation1,allocation2,allocation3;
allocation1 = new byte[_1MB / 4];
allocation2 = new byte[4 * _1MB];
allocation3 = new byte[4 * _1MB];
allocation3 = null;
allocation3 = new byte[4 * _1MB];
}
}
测试结果:
[GC[DefNew
Desired survivor size 524288 bytes, new threshold 1 (max 1)
- age 1: 768272 bytes, 768272 total
: 5515K->750K(9216K), 0.0050436 secs] 5515K->4846K(19456K), 0.0051715 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]
[GC[DefNew
Desired survivor size 524288 bytes, new threshold 1 (max 1)
- age 1: 256 bytes, 256 total
: 5094K->0K(9216K), 0.0015457 secs] 9190K->4845K(19456K), 0.0016256 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
Heap
def new generation total 9216K, used 4178K [0x04400000, 0x04e00000, 0x04e00000)
eden space 8192K, 51% used [0x04400000, 0x04814828, 0x04c00000)
from space 1024K, 0% used [0x04c00000, 0x04c00100, 0x04d00000)
to space 1024K, 0% used [0x04d00000, 0x04d00000, 0x04e00000)
tenured generation total 10240K, used 4845K [0x04e00000, 0x05800000, 0x05800000)
the space 10240K, 47% used [0x04e00000, 0x052bb6e8, 0x052bb800, 0x05800000)
compacting perm gen total 12288K, used 1672K [0x05800000, 0x06400000, 0x09800000)
the space 12288K, 13% used [0x05800000, 0x059a2248, 0x059a2400, 0x06400000)
说明:发生了两次Minor GC,第一次是在给allocation3进行分配的时候会出现一次Minor GC,此时survivor区域不能容纳allocation2,但是可以容纳allocation1,所以allocation1将会进入survivor区域并且年龄为1,达到了阈值,将在下一次GC时晋升到老年代,而allocation2则会通过担保机制进入老年代。第二次发生GC是在第二次给allocation3分配空间时,这时,allocation1的年龄加1,晋升到老年代,此次GC也可以清理出原来allocation3占据的4MB空间,将allocation3分配在Eden区。所以,最后的结果是allocation1、allocation2在老年代,allocation3在Eden区。
五、动态对象年龄判定
虚拟机并未要求对象一定要达到年龄阀值后,才可进入老年代。当Survivor空间中所有相同年龄对象大小的总和大于Survivor空间的一半,年龄大于或等于该年龄的对象也可直接进入老年代。
测试代码:
/**
* -verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8
* -XX:MaxTenuringThreshold=15 -XX:+PrintTenuringDistribution
*/
public class TestTenuringThreshold2 { private static final int _1MB = 1024 * 1024; public static void main(String[] args) {
byte[] allocation1,allocation2,allocation3,allocation4;
allocation1 = new byte[_1MB / 4];
//application1+application2大于Survivor空间一半
allocation2 = new byte[_1MB / 4];
allocation3 = new byte[4 * _1MB];
allocation4 = new byte[4 * _1MB];
allocation4 = null;
allocation4 = new byte[4 * _1MB];
}
}
测试结果:
[GC[DefNew
Desired survivor size 524288 bytes, new threshold 1 (max 15)
- age 1: 1030592 bytes, 1030592 total
: 5771K->1006K(9216K), 0.0042280 secs] 5771K->5102K(19456K), 0.0043710 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC[DefNew
Desired survivor size 524288 bytes, new threshold 15 (max 15)
- age 1: 256 bytes, 256 total
: 5350K->0K(9216K), 0.0016450 secs] 9446K->5102K(19456K), 0.0017286 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
Heap
def new generation total 9216K, used 4178K [0x04400000, 0x04e00000, 0x04e00000)
eden space 8192K, 51% used [0x04400000, 0x04814828, 0x04c00000)
from space 1024K, 0% used [0x04c00000, 0x04c00100, 0x04d00000)
to space 1024K, 0% used [0x04d00000, 0x04d00000, 0x04e00000)
tenured generation total 10240K, used 5101K [0x04e00000, 0x05800000, 0x05800000)
the space 10240K, 49% used [0x04e00000, 0x052fb798, 0x052fb800, 0x05800000)
compacting perm gen total 12288K, used 1672K [0x05800000, 0x06400000, 0x09800000)
the space 12288K, 13% used [0x05800000, 0x059a2260, 0x059a2400, 0x06400000)
结果说明:发生了两次Minor GC,第一次发生在给allocation4分配内存时,此时allocation1、allocation2将会进入survivor区,而allocation3通过担保机制将会进入老年代。第二次发生在给allocation4分配内存时,此时,survivor区的allocation1、allocation2达到了survivor区容量的一半,将会进入老年代,此次GC可以清理出allocation4原来的4MB空间,并将allocation4分配在Eden区。最终,allocation1、allocation2、allocation3在老年代,allocation4在Eden区。
六、空间分配担保
在发生Minor GC之前,虚拟机会先检查老年代最大连续空间是否大于新生代所有对象大小总和。若成立,则说明Minor GC是安全的。否则,虚拟机需要查看HandlePromotionFailure的值,看是否运行担保失败,若允许,则虚拟机继续检查老年代最大可用的连续空间是否大于历次晋升到老年代对象的平均大小,若大于,将尝试进行一次Minor GC;若小于或者HandlePromotionFailure设置不运行冒险,那么此时将改成一次Full GC,以上是JDK Update 24之前的策略,之后的策略改变了,只要老年代的连续空间大于新生代对象总大小或者历次晋升的平均大小就会进行Minor GC,否则将进行Full GC。
冒险是指经过一次Minor GC后有大量对象存活,而新生代的survivor区很小,放不下这些大量存活的对象,所以需要老年代进行分配担保,把survivor区无法容纳的对象直接进入老年代。
具体的流程图如下:
《深入理解java虚拟机》笔记(6)内存分配与回收策略的更多相关文章
- Java虚拟机面试重点-------------内存分配和回收策略
1 对象优先分配在Eden区 对象优先在Eden进行分配,大多数情况下,对象在新生代Eden区进行分配.当Eden区没有足够的空间进行分配时,虚拟机会发起一次Minor GC. 新生代GC(Ninor ...
- 《深入理解 java 虚拟机》学习 -- 内存分配
<深入理解 java 虚拟机>学习 -- 内存分配 1. Minor GC 和 Full GC 区别 概念: 新生代 GC(Minor GC):指发生在新生代的垃圾收集动作,因为 Java ...
- 转!!Java虚拟机堆的内存分配和回收
Java内存分配和回收,主要就是指java堆的内存分配和回收.java堆一般分为2个大的区域,一块是新生代,一块是老年代.在新生代中又划分了3块区域,一块eden区域,两块surviver区域.一般称 ...
- 深入理解java虚拟机笔记Chapter3-内存分配策略
内存分配策略 新生代和老年代的 GC 操作 新生代 GC 操作:Minor GC 发生的非常频繁,速度较块. 老年代 GC 操作:Full GC / Major GC 经常伴随着至少一次的 Minor ...
- 深入理解JAVA虚拟机原理之内存分配策略(二)
更多Android高级架构进阶视频学习请点击:https://space.bilibili.com/474380680 1.对象优先在Eden分配 大多情况,对象在新生代Eden区分配.当Eden区没 ...
- Java虚拟机学习 - 对象内存分配与回收 ( 5 )
对象优先在Eden上分配 大多数情况下,对象优先在新生代Eden区域中分配.当Eden内存区域没有足够的空间进行分配时,虚拟机将触发一次 Minor GC(新生代GC).Minor GC期间虚拟机将E ...
- 垃圾收集器与内存分配策略——深入理解Java虚拟机 笔记二
在本篇中,作者大量篇幅介绍了当时较为流行的垃圾回收器,但现在Java 14都发布了,垃圾收集器也是有了很大的进步和发展,因此在此就不再对垃圾收集器进行详细的研究.但其基本的算法思想还是值得我们参考学习 ...
- 深入理解Java虚拟机笔记——垃圾收集器与内存分配策略
目录 判断对象是否死亡 引用计数器算法 可达性分析算法 各种引用 回收方法区 垃圾收集算法 标记-清除算法 复制算法 标记-整理算法 分代收集算法 HotSpot算法实现 枚举根节点 GC停顿(Sto ...
- 【深入理解Java虚拟机】自动内存管理机制——垃圾回收机制
Java与C++之间有一堵有内存动态分配和垃圾收集技术所围成的"高墙",墙外面的人想进去,墙里面的人却想出来.C/C++程序员既拥有每一个对象的所有权,同时也担负着每一个对象生 ...
- Java虚拟机垃圾回收:内存分配与回收策略 方法区垃圾回收 以及 JVM垃圾回收的调优方法
在<Java对象在Java虚拟机中的创建过程>了解到对象创建的内存分配,在<Java内存区域 JVM运行时数据区>中了解到各数据区有些什么特点.以及相关参数的调整,在<J ...
随机推荐
- css书写规则
无规矩不成方圆,不管有多少人共同参与同一项目,一定要确保每一行代码都像是同一个人编写的 不要在自闭合(self-closing)元素的尾部添加斜线 不要省略可选的结束标签(closing tag)(例 ...
- hdu-5805 NanoApe Loves Sequence(线段树+概率期望)
题目链接: NanoApe Loves Sequence Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 262144/131072 ...
- 使用mutt+msmtp做linux邮件客户端
下载MSMTP wget http://nchc.dl.sourceforge.net/sourceforge/msmtp/msmtp-1.4.17.tar.bz2 tar xvf msmtp-1 ...
- 华为USG6500系列
华为USG6500: ssh 登录配置 time-range 相关配置:<USG6000V1>system-view Enter system view, return user view ...
- VijosP1443:银河英雄传说
描述 公元五八○一年,地球居民迁移至金牛座α第二行星,在那里发表银河联邦创立宣言,同年改元为宇宙历元年,并开始向银河系深处拓展. 宇宙历七九九年,银河系的两大军事集团在巴米利恩星域爆发战争.泰山压顶集 ...
- NancyFX 第二章 Rest框架
正如你看到的,Nancy有两个主要用途. 其中第一项是作为一种通用的基于 REST 框架,可替代 ASP.NET Web API 或其他Rest工具包. 默认情况下,Nancy提供一流的路由和内容协商 ...
- PDF,IMAGE,HTML,WORD,EXCEL 互操作
http://www.cnblogs.com/lyl6796910/p/3318056.html
- [hdu6201]transaction transaction transaction(树形dp)
题意:某人在一棵树中在某处买物品,价格为i,在某处卖物品,价格为j,每单位距离花费价格1,求最大赚钱数. 解题关键:两次树形dp,分别求出每个点作为被减和被加情况下的最大值,最后取一下max即可. 该 ...
- TextBox控件TextMode="Password"時
TextBox控件TextMode="Password"時,觸發服務器端事件后,會清空掉TextBox的顯示值 2008-07-15 15:06:10| 分类: C#.NET 空 ...
- 实验楼的php比赛题,网页数据提取。
实验楼的php比赛题,网页数据提取. 题目的地址:https://www.shiyanlou.com/contests/lou5/challenges 以下代码是题目的答案 <?php head ...