Java JVM 5: 认识OOM

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/hackerdotcn/article/details/78714372

OutOfMemoryError对于Java猿们来说自然不陌生,但工作中真碰到这样的问题未免头大,那为什么会内存溢出?碰到这样的问题该怎么办?下面简单探讨。
众所周知,Java数据区包括栈、堆、方法区(直接内存),堆是用来放对象的,栈是用来放线程私有的,而方法区是存放类信息的,那么根据Java内存区域不同可以将OOM原因大致分为:

堆溢出

一般来说大部分Java的内存溢出应该属于这种情况,程序分配大量对象,且对象持有强引用的话便无法被GC回收从而造成OOM。
解决

  • 调大-Xmx参数分配更大的堆,在参数方面优化;
  • 通过MAT或Visual VM等各种工具分析大量占用堆空间的对象是否有必要,从在程序层面合理优化(比如采用享元模式实现对大量重复对象的复用)。

直接内存溢出

Java 的NIO可以直接操作直接内存,这块内存是直接向操作系统申请的堆外空间,申请速度慢但是访问速度快,适合作为可复用的、经常被访问的空间。直接内存没有被JVM完全托管,未必会触发GC,若使用不当易造成OOM。
这在32位机上可能比较明显(具体未验证),因为32位系统寻址空间为4G,其中2G用户空间,2G系统空间,实际可用内存只有2G。Java进程所有内存之和(堆、栈、直接内存及虚拟机自身内存)大于2G时便会OOM。
解决

  • 设置合理的-XX:MaxDirectMemorySize可以触发GC,若不设定默认最大可用直接内存为-Xmx的值。

永久区溢出

存放类元数据的区域,显而易见,若创建太多的类(注意是类而非对象)可能导致OOM。
解决:

  • 增加MaxPermSize的值。
  • 减少系统不必要类的数量。

过多线程导致溢出

每个线程的开启都要占用系统内存,线程数量太多也可能导致OOM,但是实际应用中估计没人会会开太多线程,往往会用线程池做到线程复用。但作为一个原因这里暂且列出。

猜你喜欢

转载自blog.csdn.net/hackerdotcn/article/details/78714372