Java虚拟机--堆的配置参数(四)

最大堆和初始堆的设置

说明:

  1. Java进程启动时,虚拟机就会分配一块初始堆空间,可以使用参数-Xms指定这块空间的大小;
  2. 如果初始堆空间耗尽,虚拟机会对堆空间继续扩展,其扩展上限为最大堆空间,最大堆空间可以使用参数-Xmx指定;

示例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/31/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虚拟机--堆的配置参数(四)_第1张图片


堆溢出处理

说明: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_40JAVA_HOME目录





你可能感兴趣的:(虚拟机,Java虚拟机)