n内存溢出(OOM)的原因
n在JVM中,有哪些内存区间?
![](https://images0.cnblogs.com/blog/497307/201507/020128081401107.png)
线程栈:32位:最大值2G
n堆溢出
![](https://images0.cnblogs.com/blog/497307/201507/020128084376847.png)
![](https://images0.cnblogs.com/blog/497307/201507/020128086403021.png)
n永久区
![](https://images0.cnblogs.com/blog/497307/201507/020128093593933.png)
nJava栈溢出
–这里的栈溢出指,在创建线程的时候,需要为线程分配栈空间,这个栈空间是向操作系统请求的,如果操作系统无法给出足够的空间,就会抛出OOM
![](https://images0.cnblogs.com/blog/497307/201507/020128096718604.png)
![](https://images0.cnblogs.com/blog/497307/201507/020128098759075.png)
n直接内存溢出
–ByteBuffer.allocateDirect()无法从操作系统获得足够的空间
![](https://images0.cnblogs.com/blog/497307/201507/020128102964247.png)
![](https://images0.cnblogs.com/blog/497307/201507/020128117658232.png)
直接内存需要GC回收,但是直接内存无法引起GC。直接内存使用满时,无法触发GC。
如果堆空间很富余,无法触发GC,直接内存可能就会溢出。如果堆空间触发GC,直接内存可以回收
nMAT使用基础
nMemory Analyzer(MAT)
![](https://images0.cnblogs.com/blog/497307/201507/020128123759645.jpg)
![](https://images0.cnblogs.com/blog/497307/201507/020128126409331.png)
![](https://images0.cnblogs.com/blog/497307/201507/020128136404160.png)
![](https://images0.cnblogs.com/blog/497307/201507/020128139845886.jpg)
![](https://images0.cnblogs.com/blog/497307/201507/020128142505573.jpg)
可以马上找到系统中什么类,占用空间最多
![](https://images0.cnblogs.com/blog/497307/201507/020128145933002.png)
![](https://images0.cnblogs.com/blog/497307/201507/020128153287143.png)
–浅堆(Shallow
Heap)与深堆(Retained Heap)
n浅堆
–一个对象结构所占用的内存大小
–![](https://images0.cnblogs.com/blog/497307/201507/020128156402815.jpg)
![](https://images0.cnblogs.com/blog/497307/201507/020128156402815.jpg)
–3个int类型以及一个引用类型合计占用内存3*4+4=16个字节。再加上对象头的8个字节,因此String对象占用的空间,即浅堆的大小是16+8=24字节
–对象大小按照8字节对齐
–浅堆大小和对象的内容无关,只和对象的结构有关
n深堆
–一个对象被GC回收后,可以真实释放的内存大小
–只能通过对象访问到的(直接或者间接)所有对象的浅堆之和 (支配树)
jdk7后,string结构发生变化,但是向8字节对齐后,浅堆还是24字节
![](https://images0.cnblogs.com/blog/497307/201507/020128166099184.png)
![](https://images0.cnblogs.com/blog/497307/201507/020128184067369.jpg)
可以看到,所有的Point实例浅堆和深堆的大小都是16字节。而dLine对象,浅堆为16字节,深堆也是16字节,这是因为dLine对象内的两个点f和g没有被设置为null,因此,即使dLine被回收,f和g也不会被释放。对象cLine内的引用对象d和e由于仅在cLine内还存在引用,因此只要cLine被释放,d和e必然也作为垃圾被回收,即d和e在cLine的保留集内,因此cLine的深堆为16*2+16=48字节。
对于aLine和bLine对象,由于两者均持有对方的一个点,因此,当aLine被回收时,公共点a在bLine中依然有引用存在,故不会被回收,点a不在aLine对象的保留集中,因此aLine的深堆大小为16+16=32字节。对象bLine与aLine完全一致。
–显示入引用(incoming)和出引用(outgoing)
–支配树
n使用Visual
VM分析堆
njava自带的多功能分析工具,可以用来分析堆Dump
![](https://images0.cnblogs.com/blog/497307/201507/020128187658027.png)
![](https://images0.cnblogs.com/blog/497307/201507/020128189847025.png)
![](https://images0.cnblogs.com/blog/497307/201507/020128192343483.png)
![](https://images0.cnblogs.com/blog/497307/201507/020128201713797.jpg)
nTomcat OOM分析案例
nTomcat OOM
Tomcat 在接收大量请求时发生OOM,获取堆Dump文件,进行分析。
n使用MAT打开堆
n分析目的:
–找出OOM的原因
–推测系统OOM时的状态
–给出解决这个OOM的方法
![](https://images0.cnblogs.com/blog/497307/201507/020128209067938.jpg)
![](https://images0.cnblogs.com/blog/497307/201507/020128212183611.png)
![](https://images0.cnblogs.com/blog/497307/201507/020128215932796.jpg)
![](https://images0.cnblogs.com/blog/497307/201507/020128230785309.jpg)
![](https://images0.cnblogs.com/blog/497307/201507/020128236098979.png)
![](https://images0.cnblogs.com/blog/497307/201507/020128239689637.jpg)
![](https://images0.cnblogs.com/blog/497307/201507/020128243285593.png)
![](https://images0.cnblogs.com/blog/497307/201507/020128253755407.png)
n解决方法:
–1. OOM由于保存session过多引起,可以考虑增加堆大小
–2. 如果应用允许,缩短session的过期时间,使得session可以及时过期,并回收