JVM 内存参数设置
内存参数配置
Spring-Boot 程序的 JVM 内存参数设置格式(Tomcat 启动直接在 bin 目录下的 Catalina.sh 文件设置)
java -Xms2048m -Xmx2048m -Xmn1024 -Xss512k -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=256m -jar xxx-xxx.jar
关于元空间JVM 有两个:-XX:MetaspaceSize=N 和 -XX:MaxMetaspaceSize=N,对于 64 位 JVM 来说, 元空间默认是 21MB,默认的元空间的最大值是无限。
-XX:MaxMetaspaceSize: 设置元空间最大值,默认是 -1, 即不限制,或者说是受限制于本地内存大小。
-XX:MetaspaceSize:指定元空间的初始大小,以字节为单位,默认是 21M,达到该值过后就会触发 full gc 进行类型卸载,同时收集器会对该值进行调整;如果释放了大量的空间就适当降低该值;如果释放了很少的空间,那么就在不超过 -XX:MaxMetaspaceSize (如果设置)的情况下,适当提高该值。
由于调整元空间大小需要 full gc , 这是一个非常昂贵的操作,如果在启动过程中发生大量 full gc, 通常都是由于永久代或者元空间发生了大小调整,基于这种情况,一般建议在 JVM 参数将 MaxMetaspaceSize 和 MetaspaceSize 设置成一样的值,并设置得比初始值要大,对于 8G 的物理内存来说我们通常都会将这两个值设置为 256M。
堆空间内存溢出
import java.util.ArrayList; import java.util.List; public class HeapOverFlowTest { byte[] a = new byte[1024 * 1024 * 2]; // 2mb public static void main(String[] args) { List<HeapOverFlowTest> list = new ArrayList<>(); while(true) { list.add(new HeapOverFlowTest()); } } } // 输出结果 Exception in thread "main" java.lang.OutOfMemoryError: Java heap space at cn.edu.cqvie.jvm.HeapOverFlowTest.<init>(HeapOverFlowTest.java:8) at cn.edu.cqvie.jvm.HeapOverFlowTest.main(HeapOverFlowTest.java:13)
虚拟机栈内存溢出
public class StackOverFlowTest { // JVM 设置 // -Xss128k, -Xss默认1M static int count = 0; static void redo() { count++; redo(); } public static void main(String[] args) { try { redo(); System.out.println(count); } catch (Throwable t) { t.printStackTrace(); } } } // 输出结果: 栈溢出 java.lang.StackOverflowError at cn.edu.cqvie.jvm.StackOverFlowTest.redo(StackOverFlowTest.java:11) at cn.edu.cqvie.jvm.StackOverFlowTest.redo(StackOverFlowTest.java:11) at cn.edu.cqvie.jvm.StackOverFlowTest.redo(StackOverFlowTest.java:11) ....
总结:
-Xss 设置越小 count 值越小,说明一个线程栈里能够分配的栈帧就越小,但是对于 JVM 整体来说能够开启的线程数就会更多。
方法区内存溢出
- 需要注意的是 1.8 内模型中,将运行时常量池数据放入堆中,所以我们限制方法区的大小对运行时常量池的限制毫无意义。最终也只会抛出
java.lang.OutOfMemoryError: Java heap space
异常。
- 下面通过GCLib 模拟方法区溢出模拟的一个例子。
/** * -XX:MetaspaceSize=10m -XX:MaxMetaspaceSize=10m */ public class MyTest4 { public static void main(String[] args) { for (; ; ) { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(MyTest4.class); enhancer.setUseCache(false); enhancer.setCallback((MethodInterceptor) (obj, method, args1, proxy) -> proxy.invoke(obj, args1)); System.out.println("hello world"); enhancer.create(); } } } //输出结果 Caused by: java.lang.OutOfMemoryError: Metaspace at java.lang.ClassLoader.defineClass1(Native Method) at java.lang.ClassLoader.defineClass(ClassLoader.java:756) ......
JVM 监控工具
VisualVM
VisualVM 提供在 Java 虚拟机 (Java Virutal Machine, JVM) 上运行的 Java 应用程序的详细信息。在 VisualVM 的图形用户界面中,可以方便、快捷地查看多个 Java 应用程序的相关信息。
参考资料
- 《深入理解 Java 虚拟机》 第三版 周志明
- 《Java 虚拟机规范(Java SE 8 版)》 爱飞翔 周志明 等译