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的相关信息,如类名、访问修饰符、常量池、字段描述、方法描述等。当大量的类产生时填满方法区,会造成方法去溢出。
方法区溢出也是一种常见内存溢出异常,一个类如果要被垃圾收集器回收,判断条件非常苛刻。