前面学习了JVM的内存分布,今天就来验证下。顺便通过测试学习一下JVM的几个参数,不过测试是在idea中,所以先要在idea上设置JVM参数。
一、idea设置全局的JVM参数
一共三步,第一步在菜单栏Help下选择Edit Customer VM Options.......
第二步:可以看到选中后的参数,然后就可以设置常规参数,设置完成后记得重启idea。如下图:
第三步:重启后,查看结果,在idea的最右下角会显示总的和使用的,如果没有显示可以设置显示,如下图,在setting中勾选红色框那个选项,点击应用完成。
二、针对应用配置JVM参数
第一步:选择Run下面的Edit Configurations....
第二步:选择想配置的应用,然后在右侧的VM options设置JVM参数。
三、JVM内存验证
又要祭出那张内存分布图了,
如上图,程序计数器不会抛出异常,先不管了,主要是剩下几个的验证。
1、Java堆验证
从之前的学习知道,堆里面放的都是对象和数组,主要是对象。首先是控制堆大小的两个参数-Xms(初始堆大小)、-Xmx(最大对大小)。
测试应用的JVM参数设置:
-Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError
其中+HeapDumpOnOutOfMemoryError参数可以是内存溢出存储内存快照,可用于分析错误。测试结果如下图:
红框内就是创建的文件就是内存快照文件,在你的项目的工作目录下,这个是内存溢出前存储的内存情况,可以用专门的工具去分析。这里分享一个在线的分析网站,把Dump文件传上去就可以简单分析下了,网址就不打了,具体如下图:
2、虚拟机栈和本地方法栈验证
HotSpot虚拟机不区分虚拟机栈和本地方法栈(通过java -version可查看是什么虚拟机),所以一起测试了。对应的JVM参数-Xss(每个线程的栈大小)
我们知道栈里面存的是栈帧,栈帧对应的就是线程的方法,所以只要调用的方法多就可以测试出来,最好的办法就是递归了。
测试应用的参数配置:
-Xss128k -XX:+HeapDumpOnOutOfMemoryError
测试结果如下图:
虚拟机栈之前说过有两种溢出,线程请求的栈深度大于虚拟机允许的深度,将抛出StackOverflowError异常。如果虚拟机栈可以动态扩展,当扩展的时候没有申请到内存的时候抛出OutOfMemoryError。
这里我们是第一种情况。对于第二种情况,如果在单线程的情况下栈去动态扩展导致内存不足,那么应该也是属于栈不能申请到更多空间,所以是栈溢出,可以明显看出来OutOfMemoryError和StackOverflowError存在包含关系。如果在多个线程下。每个线程的栈都在扩展内存,就会耗光物理内存而造成了OutOfMemoryError。
一个机器的内存是有限的。建立过多线程导致的内存溢出。如果不能减少线程,那么可以通过减少堆和减少栈容量来换取更多线程。这部分可以深入讨论,主要讨论各个模块的关系,和各自的限制。
3、方法区验证
方法区中主要存储被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码。所以我们平时遇到的这类异常一般都是加载的类太多,比如spring这类的框架都会对类进行增强,都会使用到CGLib这类字节码技术,增强的类越多,就需要越大的方法区来保证动态生态的Class可以加载入内存。
jdk8的方法区变成了元空间,使用的是直接内存。所以和jdk7使用的参数不一样具体参数如下:
jdk7:-XX:PermSize=10m -XX:MaxPermSize=10m
jdk8:-XX:MetaspaceSize=10m -XX:MaxMetaspaceSize=10m
结果如下图:
jdk8的异常更加明显,明确表明是了元空间内存溢出。
4、直接内存验证
直接内存如果不设置和-Xmx(堆最大)一样。可通过参数-XX:MaxDirectMemorySize来设置直接内存。直接内存一般和NIO有关,DirectByteBuffer中通过Unsafe去操作的直接内存,DirectByteBuffer是通过计算知道内存不足抛出的异常,unsafe.allocateMemory()才是去申请内存的方法。测试代码如下图:
测试参数:-Xms20m -XX:MaxDirectMemorySize=10m
直接内存的溢出比较简单,dump文件也比较小。如果发现内存溢出也没有明显异常,dump文件比较小,那么就应该想到可以能直接内存溢出,是不是程序中使用了NIO的原因。
四、总结
学习了几个常用JVM参数,总结如下
OutOfMemoryError简称OOM,学习了几个基本的内存溢出后,对以后才能有更好的帮助。工作中遇到了内存溢出时,能根据异常信息来判断是那个区域的内存溢出,也知道什么样的代码可能会造成这些区域会出现内存溢出,并且知道一些处理手段。
Java程序员日常学习笔记,如理解有误欢迎各位交流讨论!
领取专属 10元无门槛券
私享最新 技术干货