1,Java内存溢出包括:堆内存溢出和栈内存溢出

首先说下:内存溢出和内存泄露

内存溢出:out of memory 是指程序申请内存时没有足够的空间了

内存泄露: memroy leak,是指程序申请内存后,无法释放已申请的内存空间。

内存泄露-》内存溢出

堆内存溢出:

排查方法:mat(memory analyzer tool)

-vmargs:后面跟VM参数

-Xms20M     -Xmx20M 堆内存的设置

-XX:PermSize = 40M 非堆内存

-XX:HeapDumpOnOutOfMemoryError :让虚拟机出现内存溢出时dump出此时的堆内存转储快照。

-XX:HeapDumpOnCtrBreak

-xss 设置栈内存

获取转存储文件的方法:

1.任务管理器

2.jvisiualVM工具

3.jmp,jconsole,jhat工具

mat 查看内存使用情况

(1)整体内存的消耗情况(overview)

(2)分析可以对象

 

优化从两个层面上来优化:

(1)非代码层面:-Xms  -Xmx

(2)代码层面

内存溢出的几种方式:

一. java堆溢出

创建对象没有及时回收,

1. dump出来堆转储快照 2. 使用MAT工具对dump出来的堆转储快照进行分析,重点是确认内存中得对象是否必要的,这样可以分清楚到底是出现了内存泄露(Memory Leak)还是内存溢出(Memory Overflow) 

3. 如果是内存泄露,进一步通过MAT工具分析泄露对象到GC Roots的引用链。找到泄露对象是通过怎样的路径与GC Roots相关联并导致垃圾收集器无法自动回收的。 4. 如果不存在泄露,那么就是内存中得对象却是都还必须活着,就应当检查虚拟机的堆参数(-Xmx与-Xms),与机器物理内存对比看是否可以调大

二. 虚拟机和本地方法栈溢出

 

在单线程下,无论是由于栈帧太小还是虚拟机栈容量太小,当内存无法分配的时候,虚拟机抛出的都是StackOverflowError异常。 在多线程下,通过不断的建立线程的方式可以产生内存溢出OutOfMemoryError异常。

在多线程情况下,给每个线程分配的内存越大,越容易产生内存溢出异常。由于操作系统分配给每个进程的内存是有限的,32位的Windows限制为2GB。虚拟机提供了参数来控制Java堆和方法区的这两部分内存的最大值。剩余的2GB减去Xmx,再减去MaxPermSize,忽略掉很小的程序计数器内存。如果虚拟机进程本身耗费的内存不计算,剩下的内存就是有虚拟机栈和本地方法栈瓜分了。此时如果每个线程分配到的虚拟机栈容量越大,可以建立的线程数量自然就越少,建立线程时就越容易把剩下的内存耗尽。 如果建立过多线程导致的内存溢出,在不能减少线程数或者更换64位虚拟机的情况下,就只能通过减少最大堆或者减少栈容量来获取更多的线程。

出现StackOverflowError的时候有错误堆栈可以读,即时加入+HeapDumpOnOutOfMemoryError也不会dump异常堆内存。

 

三.   运行时常量池溢出(PermGen space)

 

 

如果要项运行时常量池中添加内容,最简单的方法就是使用String.intern()这个Native方法。

异常信息:

四. 方法区溢出

 

方法区用于存放Class的相关信息,如类名、访问修饰符、常量池、字段描述、方法描述等。当大量的类产生时填满方法区,会造成方法去溢出。

方法区溢出也是一种常见内存溢出异常,一个类如果要被垃圾收集器回收,判断条件非常苛刻。