Metaspace内存溢出
Metaspace这块区域一般很少发生内存溢出,如果发生内存溢出一般都是因为两个原因:
- 不懂JVM的运行原理,在上线系统的时候对Metaspace区域直接用默认的参数,即根本不设置其大小这会导致默认的Metaspace区域可能才几十MB而已,此时对于一个稍微大型一点的系统,因为有很多类,还依赖了很多外部的jar包有有很多的类,几十MB的Metaspace很容易就不够
- 用cglib之类的技术动态生成一些类,一旦代码中没有控制好,导致你生成的类过于多的时候,就很容易把Metaspace给塞满,进而引发内存溢出
模拟案例
maven引入
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
java代码
public class Demo3 {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(Test.class);
enhancer.setUseCache(false);
enhancer.setCallback((MethodInterceptor) (o, method, objects, methodProxy) -> {
if (method.getName().equals("run")) {
System.out.println("反射执行");
}
return method.invoke(o, objects);
});
Test test = (Test) enhancer.create();
test.run();
}
static class Test {
public void run() {
System.out.println("测试代码。。。。");
}
}
}
Caused by: java.lang.OutOfMemoryError: Metaspace
栈内存溢出
如果不停的让线程调用方法,不停的往栈里放入栈桢,此时终有一个时刻,大量的栈桢会消耗完毕这个1MB的线程栈内存,最终就会导致出现栈内存溢出的情况,一般来说,其实引发栈内存溢出,往往都是代码里写了一些bug才会导致的,正常情况下发生的比较少
模拟案例
public class Demo4 {
public static void main(String[] args) {
test();
}
public static void test(){
test();
}
}
Exception in thread "main" java.lang.StackOverflowError at com.silly.demo.jvm.Demo4.test(Demo4.java:12)
堆内存溢出
有限的内存中放了过多的对象,而且大多数都是存活的,此时即使GC过后还是大部分都存活,所以要继续放入更多对象已经不可能,此时只能引发内存溢出问题。所以一般来说发生内存溢出有两种主要的场景:
- 系统承载高并发请求,因为请求量过大,导致大量对象都是存活的,所以要继续放入新的对象实在是不行了,此时就会引发OOM系统崩溃
- 系统有内存泄漏的问题,就是莫名其妙弄了很多的对象,结果对象都是存活的,没有及时取消对他们的引用,导致触发GC还是无法回收,此时只能引发内存溢出,因为内存实在放不下更多对象了
因此总结起来,一般引发OOM,要不然是系统负载过高,要不然就是有内存泄漏的问题
这个OOM问题,一旦你的代码写的不太好,或者设计有缺陷,还是比较容易引发的,所以这个问题也是我们后面要重点分析的。
模拟案例
public class Demo5 {
public static void main(String[] args) {
List<Object> list = new ArrayList<>();
while (true) {
list.add(new Object());
}
}
}
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space at java.util.Arrays.copyOf(Arrays.java:3210) at java.util.Arrays.copyOf(Arrays.java:3181) at java.util.ArrayList.grow(ArrayList.java:265) at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:239) at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:231) at java.util.ArrayList.add(ArrayList.java:462) at com.silly.demo.jvm.Demo5.main(Demo5.java:14)
OOM的时候自动dump内存快照
我们可以让他在OOM时dump一份内存快照,事后我们只要分析这个内存快照,一下就可以知道是哪些可恶的对象占用了所有的内
存,并且还无法释放。此时你就需要在JVM的启动参数中加入如下的一些参数:
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/usr/local/app/oom