面试系列----谈谈对OOM的认识
面试系列----谈谈对OOM的认识
0.什么是OOM
OOM,全称“Out Of Memory”,翻译成中文就是“内存用完了”,来源于java.lang.OutOfMemoryError。看下关于的官方说明: Thrown when the Java Virtual Machine cannot allocate an object because it is out of memory, and no more memory could be made available by the garbage collector. 意思就是说,当JVM因为没有足够的内存来为对象分配空间并且垃圾回收器也已经没有空间可回收时,就会抛出这个error(注:非exception,因为这个问题已经严重到不足以被应用处理)。
1.OOM的类型
-
Java.lang.StackOverflowError:这是一种常见的栈溢出的Error,不会抛OOM Error,但也是比较常见的Java内存溢出。JAVA虚拟机栈溢出,一般是由于程序中存在死循环或者深度递归调用造成的,栈大小设置太小也会出现此种溢出。可以通过虚拟机参数-Xss来设置栈的大小
-
Java.lang.OutOfMemoryError:Java heap space:java堆内存溢出,此种情况最常见,一般由于内存泄露或者堆的大小设置不当引起。对于内存泄露,需要通过内存监控软件查找程序中的泄露代码,而堆大小可以通过虚拟机参数-Xms,-Xmx等修改。
-
Java.lang.OutOfMemeoryError:GC overhead limit exceeded:GC回收时机过长时会抛出OutOfMemeoyError。过长的定义就是。超过98%的时间用来做GC并且GC回收了不到2%的堆内存,连续GC都只回收了不到2%的极端情况下才会抛出。假如不抛出GC overhead limit 错误会出现什么情况?那就是GC清理的这么点内存很快就再次填满,迫使GC再次执行,这样就形成恶性循环,CPU使用率一直是100%,而GC却没有任何成果。
-
Java.lang.OutOfMemeoryError:Direct buffer memory 写NIO程序经常使用ByteBuffer来读取或者写入数据,这是一种基于通道与缓冲区的IO方式,他可以使用Native函数库直接分配堆内存,然后通过一个存储在java堆里面DirectBuffer对象作为这块内存的引用进行操作,这样能在一些场景中显著题号性能,因为避免了在java堆和native堆中来回复制数据。
第一种方式是分配JVM堆内存,属于GC管辖范围,由于需要内存拷贝所有速度相对较慢。ByteBuffer.allocate(capability)
第二种方式是分配OS本地内存,不属于GC管辖范围,由于不需要内存拷贝所以速度相对较快。
ByteBuffer.allocateDirect(capability)
但是如果不断分配本地内存,堆内存很少使用,那么JVM就不需要执行GC,DirectByteBuffer对象们就不会被回收,这时候堆内存充足,但是本地内存可能已经用光了,再次尝试分配本地内存就会出现OutOfMemoryError,那程序就直接崩溃了
-
Java.lang.OutOfMemeoryError:unable to create new native thread:高并发请求服务器时,经常出现这个异常,准确的将该native thread异常与对应的平台有关。导致的原因有许多,一是应用创建的线程太多了,一个应用进程创建多个线程,超过系统承载极限、二是服务器并不允许你的应用程序创建这么多线程,linux系统默认允许单个进程可以创建的线程数是1024个,应用创建超过了这个数量就会报Java.lang.OutOfMemeoryError:unable to create new native thread异常。
解决办法:
- 想办法降低应用程序创建线程的数量,分析应用是否真的需要创建这么多的线程,如果不是,改代码将线程数将到最低
- 对于有的应用,确实需要创建很多线程,远超linux系统默认1024个线程的限制,可以通过修改linux服务器配置,扩大linux默认限制。
-
Java.lang.OutOfMemeoryError:Metaspace:这种情况就是元空间溢出了,在元空间存放的都是虚拟机加载的类信息,常量池,静态变量,即时编译后的代码

浙公网安备 33010602011771号