网上看到一道题,“写一段程序,让其运行时的表现为触发5次ygc,然后3次fgc,然后3次ygc,然后1次fgc,请给出代码以及启动参数。”,这种题对于我这种假程序猿太难了,练练手吧!这对于jvm的GC机制是有好处的。硬着头皮试下,理解下。万一有错,明眼人指出下。
编写如下(参考网上示例):(这里也通过JAVA相关类,读取打印了JVM的初始化堆、内存信息)
package com.chl.jvm;
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;
import java.lang.management.MemoryUsage;
import java.util.ArrayList;
import java.util.List;
/**
* 需求:写一段程序,让其运行时的表现为触发5次ygc,然后3次fgc,然后3次ygc,然后1次fgc,请给出代码以及启动参数。
* VM设置:-Xms41m -Xmx41m -Xmn10m -XX:+UseParallelGC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps
* -Xms41m 堆最小值
* -Xmx41m 堆最大值
* -Xmn10m 新生代大小大小(推荐 3/8)
* -XX:+UseParallelGC 使用并行收集器
* @author chenhailong
*
* 初始化时:835k(堆内存)
* 第一次add:3907k
* 第二次add:6979k
* 第三次add: eden + survivor1 = 9216k < 6979k + 3072k,区空间不够,开始 YGC
* YGC 6979k -> 416k(9216k) 表示年轻代 GC前为6979,GC后426k.年轻代总大小9216k
*/
public class GCtest {
/**
* 最小的单位
*/
private static final int UNIT_MB = 1024 * 1024;
@SuppressWarnings({ "unchecked", "rawtypes" })
public static void main(String[] args) {
getJvmInfo();
int count = 1;
List caches = new ArrayList();
System.out.println("--初始化时已用堆值:" + ManagementFactory.getMemoryMXBean().getHeapMemoryUsage().getUsed()/1024+"k");
for (int i = 1; i <= 12; i++){
if(i==11) {
System.out.println("--caches准备添加第11次,old区内存不够,开始full GC 前先执行minor GC 第"+5+"次,FGC 第1次(触发条件:【MinorGC后存活的对象超过了老年代剩余空间】)");
}
caches.add(new byte[3 * UNIT_MB]);
if(i%2==0 && i!=10) {
System.out.println("--caches添加第"+i+"次后,eden + survivor 的内存不够,开始minor GC 第"+count+"次");
count++;
}else {
System.out.println("--caches添加第"+i+"次");
}
}
System.out.println("目前整个堆内存已经36m多,Young区6M多,Old区最大值为32M");
caches.remove(0);//释放空间,重新添加 ,如果不释放空间,会报错:java.lang.OutOfMemoryError: Java heap space 【这里这样做,主要为了防止数组对象实际大小超过堆大小】
System.out.println("--FGC开始 第2次(触发条件:晋升到老年代的大小超过了老年代剩余大小)");
caches.add(new byte[3 * UNIT_MB]);
System.out.println("本次FGC,移植了Young区的一部分到Old区,导致Young区还有3M左右");
for (int i = 0; i < 8; i++){//这里是为了下次FGC后,直接减少老年代的内存大小,从而正常YGC
caches.remove(0);
}
System.out.println("--FGC开始 第3次(触发条件:同上)");
caches.add(new byte[3 * UNIT_MB]);
for (int i = 0; i < 6; i++){
caches.add(new byte[3 * UNIT_MB]);
}
}
/**
* 通过代码打印程序的堆、内存信息
*/
public static void getJvmInfo() {
System.out.println("-----------------------JVM-Info-start----------------");
MemoryMXBean memoryMXBean = ManagementFactory.getMemoryMXBean();
MemoryUsage mu = memoryMXBean.getHeapMemoryUsage();
System.out.println("heapInfo:" + mu);
System.out.println("初始化堆:" + mu.getInit()/1024/1024 + "Mb");
System.out.println("最大堆值:" + mu.getMax()/1024/1024 + "Mb");
System.out.println("已用堆值:" + mu.getUsed()/1024/1024 + "Mb");
MemoryUsage none = memoryMXBean.getNonHeapMemoryUsage();
System.out.println("non-heap Info(非堆内存):" + none);
List args = ManagementFactory.getRuntimeMXBean().getInputArguments();
System.out.println("运行时VM参数:"+args);
System.out.println("运行时总内存"+Runtime.getRuntime().totalMemory()/1024/1024);
System.out.println("运行时空闲内存"+Runtime.getRuntime().freeMemory()/1024/1024);
System.out.println("运行时最大内存"+Runtime.getRuntime().maxMemory()/1024/1024);
System.out.println("-----------------------JVM-Info-end----------------");
System.out.println("--");
System.out.println("--");
System.out.println("--");
}
}
-----------------------JVM-Info-start----------------
heapInfo:init = 44040192(43008K) used = 855568(835K) committed = 42991616(41984K) max = 42991616(41984K)
初始化堆:42Mb
最大堆值:41Mb
已用堆值:0Mb
non-heap Info(非堆内存):init = 2555904(2496K) used = 4240760(4141K) committed = 8060928(7872K) max = -1(-1K)
运行时VM参数:[-Xms41m, -Xmx41m, -Xmn10m, -XX:+UseParallelGC, -XX:+PrintGCDetails, -XX:+PrintGCTimeStamps, -Dfile.encoding=UTF-8]
运行时总内存41
运行时空闲内存40
运行时最大内存41
-----------------------JVM-Info-end----------------
--
--
--
--初始化时已用堆值:835k
--caches添加第1次
--caches添加第2次后,eden + survivor 的内存不够,开始minor GC 第1次
0.089: [GC (Allocation Failure) [PSYoungGen: 6979K->432K(9216K)] 6979K->6584K(41984K), 0.0046451 secs] [Times: user=0.01 sys=0.00, real=0.01 secs]
--caches添加第3次
--caches添加第4次后,eden + survivor 的内存不够,开始minor GC 第2次
0.094: [GC (Allocation Failure) [PSYoungGen: 6736K->400K(9216K)] 12888K->12696K(41984K), 0.0067987 secs] [Times: user=0.01 sys=0.01, real=0.00 secs]
--caches添加第5次
--caches添加第6次后,eden + survivor 的内存不够,开始minor GC 第3次
0.102: [GC (Allocation Failure) [PSYoungGen: 6868K->384K(9216K)] 19164K->18824K(41984K), 0.0044920 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]
--caches添加第7次
--caches添加第8次后,eden + survivor 的内存不够,开始minor GC 第4次
0.107: [GC (Allocation Failure) [PSYoungGen: 6687K->384K(9216K)] 25127K->24968K(41984K), 0.0046478 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
--caches添加第9次
--caches添加第10次
--caches准备添加第11次,old区内存不够,开始full GC 前先执行minor GC 第5次,FGC 第1次(触发条件:【MinorGC后存活的对象超过了老年代剩余空间】)
0.112: [GC (Allocation Failure) [PSYoungGen: 6687K->416K(9216K)] 31271K->31144K(41984K), 0.0037305 secs] [Times: user=0.00 sys=0.01, real=0.01 secs]
0.116: [Full GC (Ergonomics) [PSYoungGen: 416K->0K(9216K)] [ParOldGen: 30728K->31032K(32768K)] 31144K->31032K(41984K), [Metaspace: 2764K->2764K(1056768K)], 0.0064116 secs] [Times: user=0.02 sys=0.00, real=0.00 secs]
--caches添加第11次
--caches添加第12次后,eden + survivor 的内存不够,开始minor GC 第5次
目前整个堆内存已经36m多,Young区6M多,Old区最大值为32M
--FGC开始 第2次(触发条件:晋升到老年代的大小超过了老年代剩余大小)
0.124: [Full GC (Ergonomics) [PSYoungGen: 6303K->3072K(9216K)] [ParOldGen: 31032K->31032K(32768K)] 37336K->34105K(41984K), [Metaspace: 2765K->2765K(1056768K)], 0.0054599 secs] [Times: user=0.01 sys=0.00, real=0.00 secs]
本次FGC,移植了Young区的一部分到Old区,导致Young区还有3M左右
--FGC开始 第3次(触发条件:同上)
0.130: [Full GC (Ergonomics) [PSYoungGen: 6303K->0K(9216K)] [ParOldGen: 31032K->12601K(32768K)] 37336K->12601K(41984K), [Metaspace: 2765K->2765K(1056768K)], 0.0044791 secs] [Times: user=0.01 sys=0.00, real=0.01 secs]
0.135: [GC (Allocation Failure) [PSYoungGen: 6275K->0K(8704K)] 18876K->18745K(41472K), 0.0010285 secs] [Times: user=0.01 sys=0.00, real=0.00 secs]
0.137: [GC (Allocation Failure) [PSYoungGen: 6257K->0K(9216K)] 25002K->24889K(41984K), 0.0009595 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
0.138: [GC (Allocation Failure) [PSYoungGen: 6274K->0K(9216K)] 31163K->31033K(41984K), 0.0015084 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
0.140: [Full GC (Ergonomics) [PSYoungGen: 0K->0K(9216K)] [ParOldGen: 31033K->31033K(32768K)] 31033K->31033K(41984K), [Metaspace: 2765K->2765K(1056768K)], 0.0023516 secs] [Times: user=0.01 sys=0.00, real=0.00 secs]
Heap
PSYoungGen total 9216K, used 3236K [0x00000007bf600000, 0x00000007c0000000, 0x00000007c0000000)
eden space 8192K, 39% used [0x00000007bf600000,0x00000007bf9290e0,0x00000007bfe00000)
from space 1024K, 0% used [0x00000007bff00000,0x00000007bff00000,0x00000007c0000000)
to space 1024K, 0% used [0x00000007bfe00000,0x00000007bfe00000,0x00000007bff00000)
ParOldGen total 32768K, used 31033K [0x00000007bd600000, 0x00000007bf600000, 0x00000007bf600000)
object space 32768K, 94% used [0x00000007bd600000,0x00000007bf44e4c0,0x00000007bf600000)
Metaspace used 2771K, capacity 4490K, committed 4864K, reserved 1056768K
class space used 299K, capacity 386K, committed 512K, reserved 1048576K