java虚拟机异常终止_【OOM】Java虚拟机常见内存溢出错误

一、引言

从事java开发的小伙伴在平时的开发工作中,应该会遇见各式各样的异常和错误,在实际工作中积累的异常或者错误越多,趟过的坑越多,就会使我们编码更加的健壮,就会本能地避开很多严重的坑。以下介绍几个Java虚拟机常见内存溢出错误。以此警示,避免生产血案。

二、模拟Java虚拟机常见内存溢出错误

1、内存溢出之栈溢出错误package com.jayway.oom;

/**

* 栈溢出错误

* 虚拟机参数:-Xms10m -Xmx10m

* 抛出异常:Exception in thread "main" java.lang.StackOverflowError

*/

public class StackOverflowErrorDemo {

public static void main(String[] args) {

stackOverflowError();

}

private static void stackOverflowError() {

stackOverflowError();

}

}

2、内存溢出之堆溢出错误package com.jayway.oom;

import java.util.Random;

/**

* 堆溢出错误

* 虚拟机参数:-Xmx10m -Xms10m

* 抛出异常:Exception in thread "main" java.lang.OutOfMemoryError: Java heap space

*/

public class JavaHeapSpaceErrorDemo {

public static void main(String[] args) {

String temp = "java";

//不断地在堆中开辟空间,创建对象,撑爆堆内存

while (true) {

temp += temp + new Random().nextInt(111111111) + new Random().nextInt(222222222);

temp.intern();

}

}

}

3、内存溢出之GC超过执行限制错误package com.jayway.oom;

import java.util.ArrayList;

import java.util.List;

/**

* GC超过执行限制错误

* 虚拟机参数:-Xms10m -Xmx10m -XX:+PrintGCDetails -XX:MaxDirectMemorySize=5m

* * 抛出异常:Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceeded

* * 导致原因:GC回收时间过长会抛出OutOfMemoryError,何为过长,即超过98%的cpu时间用来做GC垃圾回收

* 但是回收效果甚微,仅仅只有2%的CPU时间用来用户程序的工作,这种状态是很糟糕的,程序在不断地GC

* 形成恶性循环,CPU的使用率一直是满负荷的,正经活却没有干,这种情况虚拟机只好抛出错误来终止程序的执行

*

* 不断地Full GC,事倍功微

* [Full GC (Ergonomics) [PSYoungGen: 2047K->2047K(2560K)] [ParOldGen: 7167K->7161K(7168K)] 9215K->9209K(9728K), [Metaspace: 3529K->3529K(1056768K)], 0.0291829 secs] [Times: user=0.08 sys=0.02, real=0.03 secs]

*/

public class GCOverheadErrorDemo {

public static void main(String[] args) {

int i = 0;

List list = new ArrayList<>();

try {

while (true) {

list.add(String.valueOf(++i).intern());

}

} catch (Throwable e) {

System.out.println("*****************i:" + i);

e.printStackTrace();

throw e;

}

}

}

4、内存溢出之直接内存溢出错误package com.jayway.oom;

import java.nio.ByteBuffer;

/**

* 直接内存溢出错误

* 抛出异常:Exception in thread "main" java.lang.OutOfMemoryError: Direct buffer memory

* * 配置虚拟机参数:-Xms10m -Xmx10m -XX:+PrintGCDetails -XX:MaxDirectMemorySize=5m

* * 导致原因:通常NIO程序经常使用ByteBuffer来读取或者写入数据,这是一种基于通道(Channel)与缓冲区(Buffer)的IO方式,

* 它可以使用Native函数库直接分配堆外内存,然后通过一个存储在java堆里面的DirectByteBuffer对象作为这块内存的引用,

* 这样能子一些场景中显著提高性能,因为避免了在Java堆和Native内存中来回复制数据。

*

* ByteBuffer.allocate(capability):分配JVM堆内存,数据GC的管辖范围,由于需要拷贝所以速度相对较慢

*

* ByteBuffer.allocate(capability):分配OS本地内存,不属于GC管辖范围,由于不需要内存拷贝,所以速度相对较快。

*

* 但是如果不断分配本地内存,堆内存很少使用,那么JVM就不需要执行GC,DirectByteBuffer对象就不会被回收,此时如果继续分配堆外内存,

* 可能堆外内存已经被耗光了无法继续分配,此时程序就会抛出OutOfMemoryError,直接崩溃。

*

*/

public class DirectBufferMemoryErrorDemo {

public static void main(String[] args) {

//默认JVM配置的最大直接内存是总物理内存的四分之一

long maxDirectMemory = sun.misc.VM.maxDirectMemory() / 1024 / 1024;

System.out.println("配置的maxDirectMemory:" + maxDirectMemory + "MB");

ByteBuffer byteBuffer = ByteBuffer.allocateDirect(6 * 1024 * 1024);

}

}

5、内存溢出之无法创建新的本地线程package com.jayway.oom;

/**

* 内存溢出之无法创建新的本地线程

* 抛出异常:java.lang.OutOfMemoryError: unable to create new native thread

* * 描述:

* 高并发请求服务器时,经常出现java.lang.OutOfMemoryError: unable to create new native thread

* native thread异常与对应的平台有关

*

* 导致原因:

* 1、应用程序创建了太多线程了,一个应用进程创建的线程数超过系统承载极限。

* 2、操作系统并不允许你的应用进程创建这么多的线程,linux系统默认允许单个进程可以创建的线程数是1024个

*

* 解决方法:

* 1、想办法降低应用进程创建的线程数量,

* 2、如果应用程序确实需要这么多线程,超过了linux系统的默认1024个限制,可以通过修改linux服务器配置,提高这个阈值。

*

*/

public class UnableCreateNativeThreadErrorDemo {

public static void main(String[] args) {

for (int i = 0; true; i++) {

System.out.println("***************i:" + i);

//不断得创建新线程,直到超过操作系统允许应用进程创建线程的极限

new Thread(() -> {

try {

Thread.sleep(Integer.MAX_VALUE);

} catch (InterruptedException e) {

e.printStackTrace();

}

}).start();

}

}

}

6、内存溢出之元空间溢出错误package com.jayway.oom;

import org.springframework.cglib.proxy.Enhancer;

import org.springframework.cglib.proxy.MethodInterceptor;

import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**

* 元空间溢出错误

* 抛出异常:java.lang.OutOfMemoryError: Metaspace

* * 设置虚拟机参数:-XX:MetaspaceSize=8m -XX:MaxMetaspaceSize=8m

* * 描述:Java8及以后的版本使用Metaspace来替代了永久代。metaspace是方法区在HotSpot中的实现,它与持久代最大的区别在于

* Metaspace并不在虚拟机内存中而是在本地内存中。

*

* 元空间存储了以下信息:

* 1、虚拟机加载的类信息

* 2、常量池

* 3、静态变量

* 4、即时编译后的代码

*

*/

public class MetaspaceErrorDemo {

static class OOMTest {

}

public static void main(String[] args) {

int count = 0;

try {

//cglib不断创建类,模拟Metaspace空间溢出,我们不断生成类往元空间中灌,超过元空间大小后就会抛出元空间移除的错误

while (true) {

count++;

Enhancer enhancer = new Enhancer();

enhancer.setSuperclass(OOMTest.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) {

System.out.println("************多少次后发生了异常:" + count);

e.printStackTrace();

}

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值