工作中最常见的6种OOM问题
Java后端技术
共 10314字,需浏览 21分钟
·
2024-04-11 16:21
往期热门文章:
1、千万不要滥用Stream.toList(),有坑! 2、强烈建议你不要再使用Date类了!!! 3、IDEA 接口调试神器,贼好用! 4、Java内部类有坑,100%内存泄露! 5、盘点Lombok的几个骚操作 5、被问懵了,加密后的数据如何进行模糊查询?
前言
1 堆内存OOM
java.lang.OutOfMemoryError: Java heap space
public class HeapOOMTest {
public static void main(String[] args) {
List<HeapOOMTest> list = Lists.newArrayList();
while (true) {
list.add(new HeapOOMTest());
}
}
}
2 栈内存OOM
java.lang.OutOfMemoryError: unable to create new native thread
public class StackOOMTest {
public static void main(String[] args) {
while (true) {
new Thread().start();
}
}
}
建议在日常工作中,多用线程池,少自己创建线程,防止出现这个OOM。
3 栈内存溢出
递归
调用,如果递归的深度超过了JVM允许的最大深度,可能会出现栈内存溢出问题。
java.lang.StackOverflowError
public class StackFlowTest {
public static void main(String[] args) {
doSamething();
}
private static void doSamething() {
doSamething();
}
}
我们在写递归代码时,一定要考虑递归深度。即使是使用parentId一层层往上找的逻辑,也最好加一个参数控制递归深度。防止因为数据问题导致无限递归的情况,比如:id和parentId的值相等。
4 直接内存OOM
直接内存
不是虚拟机运行时数据区的一部分,也不是《Java虚拟机规范》中定义的内存区域。
NIO
,通过存在堆中的DirectByteBuffer
操作Native内存,是属于堆外内存
,可以直接向系统申请的内存空间。
java.lang.OutOfMemoryError: Direct buffer memory
public class DirectOOMTest {
private static final int BUFFER = 1024 * 1024 * 20;
public static void main(String[] args) {
ArrayList<ByteBuffer> list = new ArrayList<>();
int count = 0;
try {
while (true) {
// 使用直接内存
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(BUFFER);
list.add(byteBuffer);
count++;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} finally {
System.out.println(count);
}
}
}
5 GC OOM
GC OOM
是由于JVM在GC时,对象过多,导致内存溢出,建议调整GC的策略。
java.lang.OutOfMemoryError: GC overhead limit exceeded
-Xmx10m -Xms10m
public class GCOverheadOOM {
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(5);
for (int i = 0; i < Integer.MAX_VALUE; i++) {
executor.execute(() -> {
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
}
});
}
}
}
6 元空间OOM
JDK8
之后使用Metaspace
来代替永久代
,Metaspace是方法区在HotSpot
中的实现。
ClassMetadata
,被存储在叫做Metaspace的native memory。
java.lang.OutOfMemoryError: Metaspace
-XX:MetaspaceSize=10m -XX:MaxMetaspaceSize=10m
public class MetaspaceOOMTest {
static class OOM {
}
public static void main(String[] args) {
int i = 0;
try {
while (true) {
i++;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(OOM.class);
enhancer.setUseCache(false);
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
return methodProxy.invokeSuper(o, args);
}
});
enhancer.create();
}
} catch (Throwable e) {
e.printStackTrace();
}
}
}
往期热门文章:
1、中国程序员独立开发9年、最受欢迎的开源Redis客户端,被Redis公司收购了! 2、我在代码里面故意留个漏洞,违法吗? 3、一个现代化轻量级的跨平台 Redis 桌面客户端,支持 Mac、Windows 和 Linux 4、能用到“退休”的 600条 Linux 命令,可以解决日常99%的问题~ 5、工作六年,看到这样的代码,内心五味杂陈... 6、拒绝写重复代码,试试这套开源的 SpringBoot 组件 7、一次生产事故,来来回回搞了一个月,人麻了! 8、面试官:Git 如何撤回已 Push 的代码?问倒一大片。。。 9、SpringBoot 如何快速过滤出一次请求的所有日志? 10、千万不要把 Request 传递到异步线程里面!有坑! 10、别再用 offset 和 limit 分页了,性能太差!
评论