JVM原理实践

JVM原理实践

      光懂得一堆原理是不够的,毕竟是从别人口中说出来的,我们一起来试试吧

首先,内存溢出的几种情况及其导致原因


import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

import sun.misc.Unsafe;

/**
 * 堆内存溢出:java.lang.OutOfMemoryError
 * 栈内存溢出:java.lang.StackOverflowError
 */
public class JVMOverFlow {

	static class OOMObject {
		
	}
	/**
	 * 堆溢出
	 * -verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8 -XX:+HeapDumpOnOutOfMemoryError  -XX:HeapDumpPath=E:\jvm
	 * -verbose:gc
	 * -Xms20M			堆空闲占用
	 * -Xmx20M			堆最大占用
	 * -Xmn10M			堆最小占用
	 * -XX:+PrintGCDetails
	 * -XX:SurvivorRatio=8		存活比2:8
	 * -XX:+HeapDumpOnOutOfMemoryError	dump出当前的内存堆转储快照
	 * -XX:HeapDumpPath=E:\jvm			指定路径(转储文件)
	 */	
	public static void test1() {
		List<OOMObject> list = new ArrayList<OOMObject>();
		while(true) {
			list.add(new OOMObject());
		}
	}

	/**
	 * 栈溢出
	 * -verbose:gc -Xss128k -XX:SurvivorRatio=8 -XX:+HeapDumpOnOutOfMemoryError  -XX:HeapDumpPath=E:\jvm
	 * -verbose:gc
	 * -Xss128k					栈容量
	 * -XX:SurvivorRatio=8		存活比1:8
	 * -XX:+HeapDumpOnOutOfMemoryError	dump出当前的内存堆转储快照
	 * -XX:HeapDumpPath=E:\jvm			指定路径(转储文件)
	 */
	int stackLength = 1;
	public void test2() {
		stackLength++;
		System.out.println("id:" + Thread.currentThread().getId() + " count:" + stackLength);
		this.test2();
	}
	
	/**
	 * 堆栈同时泄漏导致的内存溢出
	 */
	public void stackLeakByThread() {
		while(true) {
			Thread t = new Thread(() -> {
				while(true) {
					
				}
			});
			t.start();
		}
	}
	
	/**
	 * [Metaspace: 2585K->2585K(1056768K)],
	 * 堆溢出
	 * -XX:PermSize=10M		方法区默认大小(已失效)
	 * -XX:MaxPermSize=10M	方法区最大大小(已失效)
	 */
	public void test3() {
		List<String> list = new ArrayList<String>();
		int i = 0;
		while(true) {
			list.add(String.valueOf(i++).intern());
		}
	}
	
	/**
	 * -XX:MaxDirectMemorySize=10M
	 */
	public void test4() throws IllegalArgumentException, IllegalAccessException {
		Field unsafeField = Unsafe.class.getDeclaredFields()[0];
		unsafeField.setAccessible(true);
		Unsafe unsafe = (Unsafe) unsafeField.get(null);
		while(true) {
			unsafe.allocateMemory(1000);
		}
	}
	
	/**
	 * 引用计数算法的缺陷
	 */
	public Object instance = null;
	public void test5() {
		JVMOverFlow objA = new JVMOverFlow();
		JVMOverFlow objB = new JVMOverFlow();
		objA.instance = objB;
		objB.instance = objA;
		objA = null;
		objB = null;
	}
	
	public static void main(String[] args) throws IllegalArgumentException, IllegalAccessException {
//		test1();
		new JVMOverFlow().test2();
//		new Thread(() -> {new JVMOverFlow().test2();}).start(); 
//		new JVMOverFlow().stackLeakByThread();
//		new JVMOverFlow().test3();
//		new JVMOverFlow().test4();
//		new JVMOverFlow().test5();
	}
	
//	[Full GC (Ergonomics) [PSYoungGen: 8192K->4607K(9216K)] [ParOldGen: 6700K->9194K(10240K)] 14892K->13802K(19456K), [Metaspace: 3015K->3015K(1056768K)], 0.0865929 secs] [Times: user=0.17 sys=0.00, real=0.09 secs] 
//	[GC (Allocation Failure) [PSYoungGen: 8192K->1021K(9216K)] 8192K->1305K(19456K), 0.0017204 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
	
}


GC策略

/**
 * GC 策略
 */
public class GCPolicy {
	private static final int _1MB = 1024 * 1024;
	
	/**
	 * 对象优先在Eden区分配
	 * VM参数:-verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8 -XX:+UseSerialGC
	  */
	@SuppressWarnings("unused")
	public static void testAllocation() {
	 	byte[] allocation1, allocation2, allocation3, allocation4;
	 	allocation1 = new byte[2 * _1MB];
	 	allocation2 = new byte[2 * _1MB];
	 	allocation3 = new byte[2 * _1MB];	// Eden:7130K Survivor:0K Tenure:0K
	 	allocation4 = new byte[4 * _1MB];  	// Eden:4728K Survivor:0K Tenure:6144K	Minor GC后
	 }
	
	/**
	 * 大对象直接进入老年代
	 * VM参数:-verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8 -XX:+UseSerialGC -XX:PretenureSizeThreshold=3145728
	 * 
	 */
	@SuppressWarnings("unused")
	public static void testPretenureSizeThreshold() {
		byte[] allocation;
		allocation = new byte[4 * _1MB];  //直接分配在老年代中
	}
	
	/**
	 * 长期存活的对象将进入老年代
	 * VM参数:-verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8 -XX:MaxTenuringThreshold=1 -XX:+UseSerialGC
	 * -XX:+PrintTenuringDistribution
	 */
	@SuppressWarnings("unused")
	public static void testTenuringThreshold() {
		byte[] allocation1, allocation2, allocation3, allocation4, allocation5;
		allocation1 = new byte[_1MB / 4];  // 什么时候进入老年代决定于XX:MaxTenuringThreshold设置
		allocation2 = new byte[4 * _1MB];
		allocation3 = new byte[4 * _1MB];
		allocation4 = new byte[4 * _1MB];
//		allocation5 = new byte[4 * _1MB];
	}

	/**
	 * 动态对象年龄判定(survivor区)
	 * VM参数:-verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8 -XX:MaxTenuringThreshold=15 -XX:+UseSerialGC
	 * -XX:+PrintTenuringDistribution
	 */
	@SuppressWarnings("unused")
	public static void testTenuringThreshold2() {
		byte[] allocation1, allocation2, allocation3, allocation4;
		allocation1 = new byte[_1MB / 4];   // allocation1+allocation2大于survivo空间一半
		allocation2 = new byte[_1MB / 4];  
		allocation3 = new byte[4 * _1MB];
		allocation4 = new byte[4 * _1MB];
		allocation4 = null;
		allocation4 = new byte[4 * _1MB];
	}
	
	/**
	 * 空间分配担保策略
	 * VM参数:-Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8 -XX:+UseSerialGC
	 *  -XX:-HandlePromotionFailure	(JDK 6 Update 24后已失效,默认打开)
	 */
	@SuppressWarnings("unused")
	public static void testHandlePromotion() {
		byte[] allocation1, allocation2, allocation3, allocation4, allocation5, allocation6, allocation7;
		allocation1 = new byte[2 * _1MB];
		allocation2 = new byte[2 * _1MB];
		allocation3 = new byte[2 * _1MB];
		allocation1 = null;
		allocation4 = new byte[2 * _1MB];
		allocation5 = new byte[2 * _1MB];
		allocation6 = new byte[2 * _1MB];
		allocation4 = null;
		allocation5 = null;
		allocation6 = null;
		allocation7 = new byte[2 * _1MB];
	}

	public static void main(String[] args) {
//		testAllocation();
//		testPretenureSizeThreshold();
//		testTenuringThreshold();
//		testTenuringThreshold2();
		testHandlePromotion();

	}
}


 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

猜你喜欢

转载自blog.csdn.net/weixin_37481769/article/details/84316177