-
Notifications
You must be signed in to change notification settings - Fork 0
Description
Java OOM归类
除了程序计数器外,虚拟机内存的其他几个运行时区域都有发生OutOfMemoryError(OOM)异常的可能
内存模型
- Error 1- Java heap space
// Java program to illustrate
// Heap error
import java.util.*;
public class Heap {
static List<String> list = new ArrayList<String>();
public static void main(String args[]) throws Exception {
Integer[] array = new Integer[10000 * 10000];
}
} 解决方案
- 检查是否存在大对象分配,或者大数组分配
- jmap dump下来在使用mat工具分析看是否有内存泄漏
- 加大-Xmx内存
- 还有一点容易被忽略,检查是否有大量的自定义的 Finalizable 对象,也有可能是框架内部提供的,考虑其存在的必要性
-
- Error 2 GC Overhead limit exceeded
这个主要说明了JVM的GC一直在运行,并且程序已经运行很慢。通常98%的时间在做GC,那么这个时候会抛出这个异常
// Java program to illustrate
// GC Overhead limit exceeded
import java.util.*;
public class Wrapper {
public static void main(String args[]) throws Exception
{
Map m = new HashMap();
m = System.getProperties();
Random r = new Random();
while (true) {
m.put(r.nextInt(), "randomValue");
}
}
} 如果你用java -Xmx100m -XX:+UseParallelGC 来运行上面的代码,那么这个错误就会抛出
Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceeded
at java.lang.Integer.valueOf(Integer.java:832)
at Wrapper.main(error.java:9)
Sun 官方对此的定义:超过98%的时间用来做GC并且回收了不到2%的堆内存时会抛出此异常。
解决方法
1、检查项目中是否有大量的死循环或有使用大内存的代码,优化代码。
2、添加参数 -XX:-UseGCOverheadLimit 禁用这个检查,其实这个参数解决不了内存问题,只是把错误的信息延后,最终出现 java.lang.OutOfMemoryError: Java heap space。
3、dump内存,检查是否存在内存泄露,如果没有,加大内存。
- Error 3 - Permgen space is thrown
java内存分为不同的区域,包括permgen area都是在JVM启动的时候指定的,这个通常是说方法区的内存太小导致的。比如加载的class超过了这个区域指定的大小
// Java program to illustrate
// Permgen Space error
import javassist.ClassPool;
public class Permgen {
static ClassPool classPool = ClassPool.getDefault();
public static void main(String args[]) throws Exception
{
for (int i = 0; i < 1000000000; i++) {
Class c = classPool.makeClass(com.saket.demo.Permgen" + i).toClass();
System.out.println(c.getName());
}
}
} 可以通过修改以下参数调整
java -XX:MaxPermSize=512m com.saket.demo.Permgen(这个已经在JAVA8 中废弃了)
- Error 4 - Metaspace
java 类元数据是分配在native 内存中的,如果这个部分的内存超出,也会抛出OOM。
// Java program to illustrate
// Metaspace error
import java.util.*;
public class Metaspace {
static javassist.ClassPool cp = javassist.ClassPool.getDefault();
public static void main(String args[]) throws Exception
{
for (int i = 0; i < 100000; i++) {
Class c = cp.makeClass("com.saket.demo.Metaspace" + i).toClass();
}
}
} 这段代码持续生成新类并且加载到元数据空间中,直到完全用完元数据空间,然后就会抛出java.lang.OutOfMemoryError: Metaspace。
解决方法
因为该OOM原因比较简单,解决方法有如下几种:
1、检查是否永久代空间或者元空间设置的过小 ( -XX:MaxMetaspaceSize)
2、检查代码中是否存在大量的反射操作
3、dump之后通过mat检查是否存在大量由于反射生成的代理类
4、放大招,重启JVM
-
Error 5 – Requested array size exceeds VM limit :
主要表示应用尝试分配一个数组大于堆的大小,就会报出这个错误,举个栗子,比如在512的内存对空间中,尝试分配一个1024M的数组就会抛出这样的错误 -
Error 6 – Request size bytes for reason. Out of swap space?
java.lang.OutOfMemoryError: Out of swap space 通常是由以下的原因造成的:- The operating system is configured with insufficient swap space.(操作系统的swap space不足)
- Another process on the system is consuming all memory resources.(别的进程占用所有的内存资源)
-
Error 7 : reason stack_trace_with_native_method
// Java program to illustrate
// new native thread error
import java.util.*;
public class GFG {
public static void main(String args[]) throws Exception
{
while (true) {
new Thread(new Runnable()
{
public void run()
{
try
{
Thread.sleep(1000000000);
}
catch (InterruptedException e)
{
}
}
}).start();
}
}
} - Error 8 Map failed
- Caused by: java.lang.OutOfMemoryError: Map failed
这个一般是由于程序使用了FileChannelImpl这个类导致的,里面用到了底层的内存映射文件,当map file个数增长,系统的启动参数上加上关闭手动GC导致的(-XX:+DisableExplicitGC),导致map file个数达到了操作系统的max_map_count后直接OOM了。
Java的FilechannelImpl在使用时,如果发现map第一次出现OOM时,会调用System.gc去回收,但是我们又在启动参数上关闭了系统System.gc的能力。最后导致map失败。
解决方法:
-XX:+DisableExplicitGC这个参数不能随便关闭,原有是有些系统或者框架使用了DirectByteBuffer和FileChannel.map。这些占用的内存达到了最大临界值的时候,需要依赖调用System.gc来强制释放。
如果这个参数关闭了,那么内存释放就无效了,看到在下面第一次出现OutofMemoryError的时候,会调用System.gc(),然后等待100ms后,再次进行map操作,如果还是失败了,那就会抛出Map failed 。
try {
var7 = this.map0(var6, var13, var15);
} catch (OutOfMemoryError var30) {
System.gc();
try {
Thread.sleep(100L);
} catch (InterruptedException var29) {
Thread.currentThread().interrupt();
}
try {
var7 = this.map0(var6, var13, var15);
} catch (OutOfMemoryError var28) {
throw new IOException("Map failed", var28);
}
} 