小龙个人认为,我们作为程序员不能太天真,不然肯定会遭到社会的毒打,比如天真的认为框架+增删改查走天下,结果面试的时候还是被面试官无情的鞭挞,什么是jvm?什么是jmm?omm怎么分析?突然被这向天三问搞懵了。
小龙会是挤出时间,会将jvm和jmm从头到尾以个人的理解更哥哥们说一遍,说的不对的地方还请哥哥们见谅,也请哥哥们帮忙指出来,小龙会探讨改正的。
进入正题
oom(Out Of Menmory Error)也就是内存溢出,小龙以堆内存溢出来为例,展示如何用JProfiler来排查oom的问题
jdk1.8及以后的堆的结构图
先看看几个控制推内存大小的常用设置
-XX:+HeapDumpOnOutOfMemoryError Dump OOM。 Dump内存快照,在出现OOM的情况下 -XX:+PrintGCDetails 打印GC垃圾回收信息 -Xmx2m 设置初始化内存为2m,也就是虚拟机启动时初始化的内存大小,默认为服务器内存的1/64 -Xms2m 设置可使用最大内存2m,最大支持内存,默认为服务器的1/4
设置VM options:-Xms50m -Xmx50m -XX:+HeapDumpOnOutOfMemoryError
贴上测试代码
public class HeapOOMTest2 { //HeapOOMTest2在初始化的时候会声明一个全局变量 byte [] xiaolong = new byte [1*1024*1024]; //1M=1*1024字节*1024字节 public static void main(String[] args) { //-XX:+HeapDumpOnOutOfMemoryError 在出现OOM的情况下下载内存快照 //-XX:+PrintGCDetails 打印GC垃圾回收信息 //-Xmx2m 初始化内存 //-Xms2m 可使用最大内存 //oom,堆内存溢出,演示 ArrayList<HeapOOMTest2> list = new ArrayList<>(); int num = 0; try { while (true) { //通过死循环不断的初始化HeapOOMTest2这个类,然后不断的创建byte [] xiaolong list.add(new HeapOOMTest2()); //num不会被累加,因为Exception捕获不了OOM,需要改成OutOfMemoryError num++; } } catch (/*OutOfMemoryError*/ Exception e) { e.printStackTrace(); } } }
接下来运行项目可定会出现oom,我们设置的初始化内存为50M,最大内存也为50M,小龙的测试是不断循环往list里面添加HeapOOMTest2这个类,且这个类在新建的时候会声明全局一个1M的大小的数组。
此时我们通过-XX:+HeapDumpOnOutOfMemoryError已经将内存快照打印到了项目的根目录下
接下来我们开始用JProfiler分析这个文件,双击打开,提前是安装了Jprofiler这个工具哦,没有这个工具的可以找小龙,小龙这里有Jprofiler11的破解版,也可以哥哥们自己去百度上搜搜,一大把。
打开之后是这样的
红色框框中的功能最为常用,先看看Thread Dump,这里明显的指出了我们的main这个线程有问题,点开main的主线程,我们就可以清晰的看到我们的代码是在哪个线程的哪一行代码出现了错误
然后我们再看看大对象Biggest Object。这回哥哥们就可以非常直观的感受到哪里的问题导致内存溢出了,有这么一个大对象叫java.util.ArrayList,它居然占用了内存的98%,而且可以定位到是byte [] xiaolong 这里出现了问题
今天小龙的展示就到这里啦,麻烦哥哥们点个赞,谢谢大家!