首先运行以下代码,查看JVM运行时的初始内存以及最大内存
public class HeapTest { public static void main(String[] args) { long maxMemory = Runtime.getRuntime().maxMemory(); //最大内存(字节) long totalMemory = Runtime.getRuntime().totalMemory(); //初始内存 System.out.println("maxMemory = " + (maxMemory / 1024 / 1024) + "MB"); System.out.println("totalMemory = " + (totalMemory / 1024 / 1024) + "MB"); } }从这段代码得知:JVM的最大内存默认为该系统内存的四分之一,如果你的电脑内存为8G,则JVM的最大内存为1720MB,差不多2G左右,初始内存默认为系统内存的64分之一,也就是120MB左右。
我们执行以下代码:
public class HeapTest { public static void main(String[] args) { String str = "hello world"; while (true){ str+=str; long maxMemory = Runtime.getRuntime().maxMemory(); //最大内存(字节) long totalMemory = Runtime.getRuntime().totalMemory(); //初始内存 long freeMemory = Runtime.getRuntime().freeMemory(); //剩余内存 System.out.println("maxMemory = " + (maxMemory / 1024 / 1024) + "MB"); System.out.println("totalMemory = " + (totalMemory / 1024 / 1024) + "MB"); System.out.println("freeMemory = " + (freeMemory / 1024 / 1024) + "MB"); System.out.println("============================"); } } }由于我们是while true,这就造成了freeMemory不断变小,totalMemory不断变大,最终造成OutOfMemoryError。
内存调优 通过-Xms524m设置初始内存 -Xmx1024m设置最大内存 -Xms524m -Xmx1200m -XX:+PrintGCDetails,还可以在运行时打印GC信息 从打印的日志中可以看到,发生了GC和FullGC,通过内存提示信息也可以看到,在堆内存中占用最大的就是伊甸区和老年区 为什么上图的GC没有满15次就发生了Full GC?
前面说道伊甸区的内存是远远大于幸存0区和幸存1区的,大部分对象在伊甸区就完成创建和销毁了,但我们创建的对象一直存在引用,当其即将占满伊甸区内存后发生GC,发现收不回,则要放入幸存0区,但由于伊甸区的对象占用内存太大,幸存0区的内存远远不够,则此时直接进入了养老区。