说明:
示例1:通过此例,说明最大堆,初始堆以及系统可用内存的含义和彼此之间的关系:
public class HeapAlloc {
public static void main(String[] args) {
//打印了基本的系统信息,包括最大可用内存,当前空闲内存和当前总内存;
System.out.println("maxMemory = ");
System.out.println(Runtime.getRuntime().maxMemory() + "bytes");
System.out.println("free mem = ");
System.out.println(Runtime.getRuntime().freeMemory() + "bytes");
System.out.println("total mem = ");
System.out.println(Runtime.getRuntime().totalMemory() + "bytes");
//申请1MB内存空间,该内存分配在堆上
byte[] b = new byte[1*1024*1024];
System.out.println("分配了1M空间给数组");
//打印最大可用内存,当前空闲内存和当前总内存;
System.out.println("maxMemory = ");
System.out.println(Runtime.getRuntime().maxMemory() + "bytes");
System.out.println("free mem = ");
System.out.println(Runtime.getRuntime().freeMemory() + "bytes");
System.out.println("total mem = ");
System.out.println(Runtime.getRuntime().totalMemory() + "bytes");
//申请4MB内存空间,该内存分配在堆上
b = new byte[4*1024*1024];
System.out.println("分配了4M空间给数组");
System.out.println("maxMemory = ");
System.out.println(Runtime.getRuntime().maxMemory() + "bytes");
System.out.println("free mem = ");
System.out.println(Runtime.getRuntime().freeMemory() + "bytes");
System.out.println("total mem = ");
System.out.println(Runtime.getRuntime().totalMemory() + "bytes");
}
}
说明:这里的最大内存是指-Xmx的取值,当前总内存应该不小于-XMs的设定,因为当前总内存总是在-Xms和-Xmx之间,从-Xms开始根据需要向上增长;而当前空闲空间应该是当前总内存减去当前已经使用的空间;使用如下参数执行程序:-Xmx20m -Xms5m -XX:+PrintCommandLineFlags -XX:+PrintGCDetails -XX:+UseSerialGC输出结果如下:
-XX:InitialHeapSize=5242880 -XX:MaxHeapSize=20971520 -XX:+PrintCommandLineFlags -XX:+PrintGCDetails -XX:+UseCompressedOops -XX:-UseLargePagesIndividualAllocation -XX:+UseSerialGC
maxMemory = 20316160bytes
free mem = 4466664bytes
total mem = 5111808bytes
[GC[DefNew: 630K->128K(1536K), 0.0059443 secs] 630K->463K(4992K), 0.0082716 secs] [Times: user=0.00 sys=0.02, real=0.01 secs]
分配了1M空间给数组
maxMemory = 20316160bytes
free mem = 3559728bytes
total mem =5111808bytes
[GC[DefNew: 1180K->0K(1536K), 0.0041030 secs][Tenured: 1487K->1487K(3456K), 0.0126827 secs] 1515K->1487K(4992K), [Perm : 2564K->2564K(21248K)], 0.0169347 secs] [Times: user=0.02 sys=0.00, real=0.02 secs]
分配了4M空间给数组
maxMemory = 20316160bytes
free mem = 3675952bytes
total mem = 9441280bytes
Heap
def new generation total 1664K, used 77K [0x00000000f9a00000, 0x00000000f9bc0000, 0x00000000fa0a0000)
eden space 1536K, 5% used [0x00000000f9a00000, 0x00000000f9a135b0, 0x00000000f9b80000)
from space 128K, 0% used [0x00000000f9b80000, 0x00000000f9b80000, 0x00000000f9ba0000)
to space 128K, 0% used [0x00000000f9ba0000, 0x00000000f9ba0000, 0x00000000f9bc0000)
tenured generation total 7556K, used 5583K [0x00000000fa0a0000, 0x00000000fa801000, 0x00000000fae00000)
the space 7556K, 73% used [0x00000000fa0a0000, 0x00000000fa613e68, 0x00000000fa614000, 0x00000000fa801000)
compacting perm gen total 21248K, used 2570K [0x00000000fae00000, 0x00000000fc2c0000, 0x0000000100000000)
the space 21248K, 12% used [0x00000000fae00000, 0x00000000fb082b88, 0x00000000fb082c00, 0x00000000fc2c0000)
No shared spaces configured.
当前的最大内存由-XX:MaxHeapSize=20971520指定,它正好是20*1024*1024=20971520字节。而打印的最大可用内存仅仅为20316160字节,比设定值略少。这是因为分配给堆的内存空间和时间可用的内存空间并非一个概念。由于垃圾回收的需要,虚拟机会堆堆空间进行分区管理,不同的区域采用不同的回收算法,一些算法会使用空间换时间的策略工作,因此会存在可用内存的损失。最终的结果就是实际可用内存会浪费大小等于from/to的空间;
提示:
在实际使用时,也可以直接将初始堆将初始值-Xms与最大堆-Xmx设置相等。这样的好处时减少程序运行时进行的垃圾回收次数,从而提高性能;
参数-Xmm:用于设置新生代的大小;设置一个较大的新生代会减小老年代的大小,这个参数对系统性能以及GC行为有很大的影响。新生代的大小一般设置为整个堆空间的1/3到1/4左右;
参数-XX:SurvivorRation:用来设置新生代中eden空间和from/to空间的比例关系,含义如下:
-XX:SurvivorRatio = eden/from=eden/to
实际工作的基本策略:尽可能将对象预留在新生代,减少老年代
GC
的次数;
参数-XX:NewRatio:设置新生代和老年代的比例,含义如下:
-XX:NewRatio=老年代/新生代
注意:
-XX:SurvivorRation
可以设置
eden
区与
survivor
区的比例;
-XX:New
R
atio
可以设置老年代与新生代的比例
图解,几个重要的堆分配参数的含义:
说明:Java程序运行时,如果堆空间不足,则有可能抛出内存溢出错误(Out Of Memory)简称为OOM,出现此问题,系统会被迫退出,如下图:
-XX:+HeapDumpOnOutOfMemoryError:该参数在内存溢出时导出整个堆信息;
-XX:HeapDumpPath:可以指定导出堆的存放路径;
示例1:测试两个参数
public class DumpOOM {
public static void main(String[] args) {
Vector v = new Vector();
for (int i = 0; i < 25; i++) {
v.add(new byte[1*1024*1024]);
}
}
}
使用如下参数运行该程序:-Xmx20m -Xms5m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=d:/a.dump分析:20MB堆空间不足以容纳25MB内存,系统发生内存溢出,控制台结果如下:
java.lang.OutOfMemoryError: Java heap space
Dumping heap to d:/a.dump ...
Heap dump file created [18971140 bytes in 0.067 secs]
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at hey.up2.DumpOOM.main(DumpOOM.java:23)
虚拟机已将当前堆信息导出,保存到d:/a.dump,可使用MAT工具打开此文件分析
示例2:除了发生OOM时导出堆信息,虚拟机还允许在发生错误时执行一个脚本文件,该文件可以用于崩溃程序的自救,报警或通知;
1.准备printstack.bat脚本:
D:/tools/jdk1.7_40/bin/jstack-F %1 > D:/a.txt
2.该脚本将会导出给定Java虚拟机进程的线程信息,并保存在D:/a.txt文件中
3.使用如下参数执行上述代码:
-Xmx20m -Xms5m"-XX:OnOutOfMemoryError=D:/tools/jdk1.7_40/bin/printstack.bat %p"-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=d:/a.dump
4.在程序异常退出时,系统D盘会生成新文件a.txt,里面保存着线程转存信息。本例中,D:/tools/jdk1.7_40为JAVA_HOME目录