JVM Runtime.maxMemory 计算方法

先上一段代码:

package com.envisioniot;

import org.springframework.boot.autoconfigure.SpringBootApplication;

import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;
import java.lang.management.MemoryPoolMXBean;
import java.util.Vector;

@SpringBootApplication
public class RuntimeMemTest {

	static String mb (long s) {
		return String.format("%d (%.2f M)", s, (double)s / (1024 * 1024));
	}

	static void getRuntimeMem() {
		System.out.println("Runtime max: " + mb(Runtime.getRuntime().maxMemory()));
		MemoryMXBean m = ManagementFactory.getMemoryMXBean();

		System.out.println("Non-heap: " + mb(m.getNonHeapMemoryUsage().getMax()));
		System.out.println("Heap: " + mb(m.getHeapMemoryUsage().getMax()));

		for (MemoryPoolMXBean mp : ManagementFactory.getMemoryPoolMXBeans()) {
			System.out.println("Pool: " + mp.getName() +
					" (type " + mp.getType() + ")" +
					" = " + mb(mp.getUsage().getMax()));
		}
	}

	public static void main(String[] args) {
		System.out.println("Let's Go");

		getRuntimeMem();

		Vector v = new Vector();
		while (true){
			int MB = 1024*1024;
			byte b[] = new byte[1024*1024]; // 1M
			v.add(b);
			Runtime rt = Runtime.getRuntime();
			System.out.println("Free Mem: " + rt.freeMemory()/MB  + "   total Memory: " + rt.totalMemory()/MB + "   Max Memory: " + rt.maxMemory()/MB);
 		}

	}
}


跑一把:

> java -version
java version "1.8.0_181"
Java(TM) SE Runtime Environment (build 1.8.0_181-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.181-b13, mixed mode)

> java -Xmx1024M -jar RuntimeMemTest.jar
Runtime max: 954728448 (910.50 M)
Non-heap: -1 (-0.00 M)
Heap: 954728448 (910.50 M)
Pool: Code Cache (type Non-heap memory) = 251658240 (240.00 M)
Pool: Metaspace (type Non-heap memory) = -1 (-0.00 M)
Pool: Compressed Class Space (type Non-heap memory) = 1073741824 (1024.00 M)
Pool: PS Eden Space (type Heap memory) = 335544320 (320.00 M)
Pool: PS Survivor Space (type Heap memory) = 11010048 (10.50 M)
Pool: PS Old Gen (type Heap memory) = 716177408 (683.00 M)
Free Mem: 236   total Memory: 245   Max Memory: 910
Free Mem: 235   total Memory: 245   Max Memory: 910
Free Mem: 234   total Memory: 245   Max Memory: 910
Free Mem: 233   total Memory: 245   Max Memory: 910
Free Mem: 232   total Memory: 245   Max Memory: 910
....
....
Free Mem: 16   total Memory: 936   Max Memory: 936
Free Mem: 15   total Memory: 936   Max Memory: 936
Free Mem: 14   total Memory: 936   Max Memory: 936
Free Mem: 13   total Memory: 936   Max Memory: 936
Free Mem: 12   total Memory: 936   Max Memory: 936
Free Mem: 11   total Memory: 936   Max Memory: 936
Exception in thread "main" java.lang.reflect.InvocationTargetException
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:48)
	at org.springframework.boot.loader.Launcher.launch(Launcher.java:87)
	at org.springframework.boot.loader.Launcher.launch(Launcher.java:50)
	at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:51)
Caused by: java.lang.OutOfMemoryError: Java heap space
	at com.envisioniot.DockerRunnerApplication.main(DockerRunnerApplication.java:39)
	... 8 more

基本概念:

maxMemory():返回Java虚拟机尝试使用的最大内存量。如果没有固有限制,则将返回值Long.MAX_VALUE。
totalMemory():返回Java虚拟机中的内存总量。此方法返回的值可能会随时间变化,具体取决于主机环境。
freeMemory():返回Java虚拟机中的可用内存量。调用gc方法可能会导致freeMemory返回的值增加。

 

问题来了,Runtime max: 954728448 (910.50 M) 为啥?

正常情况下,Runtime.maxMemory() = OldGen + NewGen - Survivor
为啥要减去一个Survivor?因为有2个Survivor区,而只有一个可以在任何给定的时间点保存活的对象

但注意了!!!前面设置了-Xmx1024m,没有设置初始堆大小并且没有关闭UseAdaptiveSizePolicy(JVM会自动调整Eden区和Survivor区的比例),所以Runtime.maxMemory会保守的估计内存量,并从NewGen中减去最大的Survivor
所以计算方法如下:
Runtime.maxMemory() = OldGen + NewGen - MaxSurvivor
MaxSurvivor = NewGen / MinSurvivorRatio

为了验证,先查下JVM几个参数默认值(当然可以自己配):

 >  > java -XX:+PrintFlagsFinal -version | egrep 'NewRatio|MinSurvivorRatio|UseAdaptiveSizePolicy' 
    uintx MinSurvivorRatio                          = 3                                   {product}
    uintx NewRatio                                  = 2                                   {product}
     bool UseAdaptiveSizePolicy                     = true                                {product}

算一下(-Xmx=1024M):
OldGen = 1024 * 2 / 3 = 682.6666  ~~ 683
NewGen = 1024 * 1 / 3 = 341.3333 ~~ 341
MaxSurvivor =  341 / 3 = 113.6666 
RunTime.maxMermory  = 683 + 341 - 113.6666 = 910.333

 


JVM参数配好再跑一把:

 > java -Xmx1024M -Xms1024M  -XX:SurvivorRatio=4  -XX:-UseAdaptiveSizePolicy -jar RuntimeMemTest.jar
Let's Go
Runtime max: 1014497280 (967.50 M)
Non-heap: -1 (-0.00 M)
Heap: 1014497280 (967.50 M)
Pool: Code Cache (type Non-heap memory) = 251658240 (240.00 M)
Pool: Metaspace (type Non-heap memory) = -1 (-0.00 M)
Pool: Compressed Class Space (type Non-heap memory) = 1073741824 (1024.00 M)
Pool: PS Eden Space (type Heap memory) = 239075328 (228.00 M)
Pool: PS Survivor Space (type Heap memory) = 59244544 (56.50 M)
Pool: PS Old Gen (type Heap memory) = 716177408 (683.00 M)
Free Mem: 953   total Memory: 967   Max Memory: 967
Free Mem: 953   total Memory: 967   Max Memory: 967
Free Mem: 952   total Memory: 967   Max Memory: 967
Free Mem: 951   total Memory: 967   Max Memory: 967
...
...
Free Mem: 63   total Memory: 967   Max Memory: 967
Free Mem: 63   total Memory: 967   Max Memory: 967
Free Mem: 62   total Memory: 967   Max Memory: 967
Free Mem: 61   total Memory: 967   Max Memory: 967
Free Mem: 60   total Memory: 967   Max Memory: 967
Free Mem: 59   total Memory: 967   Max Memory: 967
Free Mem: 58   total Memory: 967   Max Memory: 967
Free Mem: 57   total Memory: 967   Max Memory: 967
Exception in thread "main" java.lang.reflect.InvocationTargetException
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:48)
	at org.springframework.boot.loader.Launcher.launch(Launcher.java:87)
	at org.springframework.boot.loader.Launcher.launch(Launcher.java:50)
	at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:51)
Caused by: java.lang.OutOfMemoryError: Java heap space
	at com.envisioniot.DockerRunnerApplication.main(DockerRunnerApplication.java:39)
	... 8 more 

再算算(-Xmx1024M -Xms1024M  -XX:SurvivorRatio=4  -XX:-UseAdaptiveSizePolicy):
Survivor =  341 * (4+1+1) =  56.8333 ~ 56.5
Runtime.maxMemory() = 1024 - 56.5 = 967.5
完美!

 

有日子没更新了,希望对大家有帮助!

你可能感兴趣的:(java)