常用的JVM配置参数

1.Trace跟踪参数

-verbose:gc表示输出虚拟机中GC的详细情况

-XX:+printGC开启了简单GC日志模式,为每一次新生代(young generation)的GC和每一次的Full GC打印一行信息。

常用的JVM配置参数_第1张图片

-XX:+PrintGCDetails 打印GC详细信息,只会在程序结束之后才会打印堆的相关信息

-XX:+PrintGCTimeStamps打印GC发生的时间戳

常用的JVM配置参数_第2张图片

-新生代总共有13824K大小,已经使用了11223K

新生代=eden + survivor

-eden区空间为12288K,有91%被使用了

有两个大小相等的survivor区,from 和 to

-from区 有1536K 未被使用

-to区 有1536K 未被使用

-老年代tenured generation总共5120K,未被使用

-永久区的一个共享区 总共12288K,已使用142K,一些基础的java类会被加载到共享区中,供所有java虚拟机使用

-ro只读共享区大小10240K 使用了44%

-rw可读写共享区大小12288K,52%已使用

---------------------------------------------------------------------------------该部分由于首次接触,还没太熟悉,相信慢慢的会理解的

新生代在内存中间的位置

低边界:代表起始位置

当前边界:当前所被分配/所申请到的位置

最高边界:新生代能申请到的最高位置

(0x28d80000-0x27e80000)/1024/1024=15M表明新生代正好被分配了15M

15M = eden区大小+from区大小+to区大小;

新生代总共有13824K大小=eden + survivor = 12288+1536

-Xloggc:log/gc.log指定GC log的位置当前目录下log文件夹下面的路径,以文件输出,有助于帮助开发人员分析问题

-XX:+PrintHeapAtGC表示每次GC后都打印堆信息

常用的JVM配置参数_第3张图片

常用的JVM配置参数_第4张图片

GC调用前后的区别:eden区从100%被使用变成0%被使用,from区从0%used到100%used

老年代从0%uesed到已使用57k,部分数据从新生代移到了老年代。----------具体情况为什么会这样,还没了解透,不便解释

-XX:+TraceClassLoading 监控类的加载

常用的JVM配置参数_第5张图片

2.堆的分配参数

-Xmx最大堆空间  Xms最小堆空间

public class TestHeap{
	public static void main(String[] args){
		System.out.println("maxMemory:" 
				+ Runtime.getRuntime().maxMemory()/1024.0/1024 + "M");
		System.out.println("freeMemory:" 
				+ Runtime.getRuntime().freeMemory()/1024.0/1024 + "M");
		System.out.println("totalMemory:" 
				+ Runtime.getRuntime().totalMemory()/1024.0/1024 + "M");
	}
}

maxMemory()这个方法返回的是java虚拟机(这个进程)能够从操作系统那里挖到的最大的内存,以字节为单位,如果在运行java程序的时 候,没有添加-Xmx参数,那么就是64兆,这是java虚拟机默认情况下能从操作系统那里挖到的最大的内存。如果添加了-Xmx参数,将以这个参数后面的值为准。

totalMemory()这个方法返回的是java虚拟机现在已经从操作系统得到的内存大小,也就是java虚拟机这个进程当时所占用的所有内存。如果在运行java的时候没有添加-Xms参数,那么,在java程序运行的过程的,内存总是慢慢的从操作系统那里挖的,基本上是用多少分配多少,直到分配到maxMemory()为止,所以totalMemory()是慢慢增大的。如果用了-Xms参数,程序在启动的时候就会无条件的从操作系统中挖接近- Xms后面定义的内存数,然后在这些内存用的差不多的时候,再去申请空间。

freeMemory()是什么呢,刚才讲到如果在运行java的时候没有添加-Xms参数,那么,在java程序运行的过程的,内存总是慢慢的从操作系统那里申请的,基本上是用多少申请多少,但是java虚拟机100%的情况下是会稍微多挖一点的,这些挖过来而又没有用上的内存,实际上就是 freeMemory(),所以freeMemory()的值一般情况下都是很小的,但是如果你在运行java程序的时候使用了-Xms,这个时候因为程序在启动的时候就会无条件的从操作系统中申请-Xms后面定义的内存数,这个时候,申请过来的内存可能大部分没用上,所以这个时候freeMemory()可能会有些大。

上述代码中增加了该语句

byte[] b = new byte[1 * 1024 *1024];

byte[] b = new byte[5 * 1024 *1024];

将其增大后,原来该进程所申请的5.5M空间不够了,就会继续申请

byte[] b = new byte[5 * 1024 *1024];
System.gc();
//加入GC之后

空闲内存大小增多了

-Xmn设置新生代的大小,表示新生代的绝对值

-XX:NewRatio 新生代(eden + 2*s)和老年代(不包含永久区)的比值,例如4表示新生代:老年代=1:4,年轻代占堆的1/5

-XX:SurvivorRatio

  -设置两个Survivor区和eden的比

  8表示(from + to):eden=2:8,即每个survivor占1/10

public class TestHeap2{
	public static void main(String[] args){
		byte[] b = null;
		for(int i = 0; i < 10; i++){
			b = new byte[1 * 1024 * 1024];
		}
	}
}

此时如果将-Xmn设置为1M,系统发出警告,当前分配的新生代大小1M过小了,系统会将其修改为1536k,将新生代大小改为2M就没有错误了。但是这个错误详细解释查阅很多资料没找到,表示有点迷糊。不清楚是不是Jdk1.8不能设置-Xmn为1M

java -Xmx20m -Xms20m -Xmn2m -XX:+PrintGCDetails TestHeap2

常用的JVM配置参数_第6张图片

常用的JVM配置参数_第7张图片

java -Xmx20m -Xms20m -Xmn2m -XX:+PrintGCDetails TestHeap2

常用的JVM配置参数_第8张图片

使用该命令,内存申请大小虽然为1M,加上本身系统的资源,年轻代的2M无法满足需求,所以10M的内存分配都放到了老年代。

java -Xmx20m -Xms20m -Xmn3m -XX:+PrintGCDetails TestHeap2

此时新生代分配了3m空间,从上述两个堆分配中可知,内存申请为1M加上系统资源,资源内存处于2m-3m的范围,所以将申请的一个1m内存分配到了年轻代,其余9m的内存申请放到了老年代。此处没有发生GC有点疑惑。

java -Xmx20m -Xms20m -Xmn15m -XX:+PrintGCDetails TestHeap2

常用的JVM配置参数_第9张图片

没有发生分配失败和GC回收。 10M的分配都进入了Eden区域。 年老代中为0, Survivior区域为0.

java -Xmx20m -Xms20m -Xmn7m -XX:+PrintGCDetails TestHeap2

常用的JVM配置参数_第10张图片

发生两次GC,回收空间大约在5m左右,eden区分配了6M左右空间,from和to分配512k,不足以放下内存申请的1M空间,所以老年代还是有部分的内存被分配了(刚开始了解虚拟机,很多知识还不懂,到后面学了垃圾回收和内存分配,再回来看看这个情况)

java -Xmx20m -Xms20m -Xmn7m -XX:SurvivorRatio=2 -XX:+PrintGCDetails TestHeap2

常用的JVM配置参数_第11张图片

此时新生代中的from和to,已经超过了内存申请的1m大小,可以被分配内存,所以出发了三次GC,每次回收大约3M,基本不会在老年代进行内存分配,加上系统级别对象资源的占用,所以老年代依然有内存使用状况。

java -Xmx20m -Xms20m -XX:NewRatio=1 -XX:SurvivorRatio=2 -XX:+PrintGCDetails TestHeap2

常用的JVM配置参数_第12张图片

NewRatio为1, 则新生代和年老代的比例是1:1, 都为10M。 SurvivorRatio为2, 则2个survior:eden = 2:2, 平均分配, 5m, 2.5m, 2.5m

java -Xmx20m -Xms20m -XX:NewRatio=1 -XX:SurvivorRatio=4 -XX:+PrintGCDetails TestHeap2

常用的JVM配置参数_第13张图片

增加eden区的大小,减少survivor区的大小能够减少GC的发生,GC次数下降后,很多新生代的对象就无法晋升到老年代了

-XX:+HeapDumpOnOutOfMemoryError 表示OOM时导出堆到文件

-XX:HeapDumpPath  导出OOM文件的路径设置(一定得注意如果加了+号下面就会报错)Unexpected +/- setting in VM option 'HeapDumpPath=e:\oom.dump'

-XX:OnOutOfMemoryError 在OOM时,执行一个脚本

import java.util.Vector;
public class TestHeap3{
	public static void main(String[] args){
		Vector v = new Vector();
		for(int i = 0; i < 25; i++){
			v.add(new byte[1 * 1024 * 1024]);
		}
	}
}

java -Xmx20m -Xms5m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=e:\project\JVM\oom.dump TestHeap3

在jdk目录的bin文件夹中的jvisualvm.exe可以打开dump文件

常用的JVM配置参数_第14张图片

因为byte数组分配了过多的内存,超过最大堆的大小20m,所以发生OOM

总结

常用的JVM配置参数_第15张图片

永久区分配参数

-XX:PermSize 永久区的初始空间大小

-XX:MaxPermSize 永久区的最大空间

系统启动之后所分配的永久区的空间,接近于-XX:PermSize的值,如果空间不够,可以扩大,但是不能超过MaxPermSize

他们表示,一个系统可以容纳多少个类型

 

使用CGLIB等库的时候,会产生大量类,这些类,有可能会撑爆永久区导致OOM

如果堆空间没有用完也可能抛出OOM,可能是永久区溢出导致的

3.栈的分配参数

-Xss为栈分配空间

   -通常只有几百k

   -决定了函数调用的深度

   -每个线程上都有独立的空间

   -局部变量、参数分配在栈上

 

你可能感兴趣的:(JVM(Java,Virtual,Machine))