既然选择了远方,即使天寒地冻,路遥马亡,我本就一无所有,又有何惧。
OOM(内存溢出)是一个让人很头疼的问题,出现 OOM 的问题有很多,下面就 OOM 可能出现的原因进行介绍。
1、堆空间太小
用以下参数启动 jvm
-Xms20m -Xmx20m
public class OOMTest {
public static void main(String[] args) {
Byte[] bs = new Byte[1024 * 1024 * 30];
}
}
最大堆、初始化堆均为 20m,程序创建了 30m 的数组,直接 OOM。
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
1.1、处理方式
- 调大
-Xmx
的值 - 通过内存分析工具,找出占用内存较多的对象
2、直接内存溢出
直接内存属于堆外内存,是直接向操作系统申请内存空间。
直接内存申请速度一般小于堆内存的申请速度,但是访问速度会比堆内存的访问速度快。
直接内存并没有完全的归 GC
管理,使用不当,也会造成 OOM
。
2.1、直接内存不足,溢出
用以下参数启动 jvm
-Xms20m -Xmx20m
public class OOMTest {
public static void main(String[] args) {
while (true) {
ByteBuffer.allocateDirect(1024 * 1024 * 30);
}
}
}
直接内存最大值为 20m, 所以直接溢出
Exception in thread "main" java.lang.OutOfMemoryError: Direct buffer memory
at java.nio.Bits.reserveMemory(Bits.java:694)
at java.nio.DirectByteBuffer.<init>(DirectByteBuffer.java:123)
at java.nio.ByteBuffer.allocateDirect(ByteBuffer.java:311)
at com.csp.boot.jvm.OOMTest.main(OOMTest.java:14)
注:直接内存最大值,默认为 -Xmx
配置的值
2.2、处理方式
- 调小
-Xmx
的值,让操作系统有更多的内存分配给直接内存 - 避免一次性分配太大的直接内存
- 设置合理的
-XX:MaxDirectMemorySize
2.3、直接内存回收
直接内存只有在使用量触到 -XX:MaxDirectMemorySize
时,才会触发 GC
,具体看下面 demo
用以下参数启动 jvm
-Xms20m -Xmx20m -verbose:gc
public class OOMTest {
public static void main(String[] args) {
while (true) {
ByteBuffer.allocateDirect(1024 * 1024 * 1);
}
}
}
启动后,会在程序控制台,看到有 GC 日志不断的输出
[GC (System.gc()) 2474K->731K(19968K), 0.0016716 secs]
[Full GC (System.gc()) 731K->631K(19968K), 0.0043987 secs]
3、线程过多
在 java 内存模式中,虚拟机栈,本地方法栈,程序计算器 这些都是线程独有的,线程本身也占用内存空间,如果线程启用太多,会直接导致 OOM
用以下参数启动 jvm
-Xms20m -Xmx20m
public class OOMTest {
public static void main(String[] args) {
while (true) {
new Thread(() -> {
try {
Thread.sleep(30000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
}
}
Exception in thread "main" java.lang.OutOfMemoryError: unable to create new native thread
at java.lang.Thread.start0(Native Method)
at java.lang.Thread.start(Thread.java:717)
at com.csp.boot.jvm.OOMTest.main(OOMTest.java:19)
3.1、处理方式
- 适当调低
-Xss
的值,可使jvm
创建更多的线程
4、GC 效率低下
当 GC 效率低下时,也会出现 oom
。GC 效率低下导致的 oom
条件苛刻,但是还是不可避免会出现
4.1、触发条件
- 花在 GC 的时间上,超过 98%
- 老年代释放的内存小于 2%
- 新生代释放的内存小于 2%
- 连续 5 次 GC 都出现以上情况
触发后,会抛出以下异常
注:必须满足以上所有条件,才会触发
5、内存泄露
出现内存泄露的原因,主要是对象已经无用了,但是却无法被回收。从而可使用的内存越来越少,最终触发 OOM
.
找出内存泄露的罪魁祸首一般需要借助内存分析工具,进行分析。这一部分的内容比较多,会放到下一章节来说。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。