1.8 内存溢出实战

堆内存溢出

1.代码示例

public class HeapOOMDemo {
    private List<String> oomList = new ArrayList<>();

    public static void main(String[] args) {
        HeapOOMDemo heapOOMDemo = new HeapOOMDemo();
        while (true) {
            heapOOMDemo.oomList.add(UUID.randomUUID().toString());
        }
    }
}

2.设置堆最小和最大内存并让应用在堆内存溢出的时候,进行一次堆Dump

-Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError

在这里插入图片描述

3.执行程序,输出如下结果

java.lang.OutOfMemoryError: GC overhead limit exceeded
Dumping heap to java_pid1416.hprof ...
Heap dump file created [21291311 bytes in 0.084 secs]
Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceeded
	at java.util.Arrays.copyOfRange(Arrays.java:3664)
	at java.lang.String.<init>(String.java:207)
	at java.lang.StringBuilder.toString(StringBuilder.java:407)
	at java.util.UUID.toString(UUID.java:380)
	at com.steven.HeapOOMDemo.main(HeapOOMDemo.java:14)

4.使用jvisualvm载入Dump的堆内存快照
在这里插入图片描述
由下面信息定位到问题代码出现在HeapOOMDemo.java的14行。

"main" prio=5 tid=1 RUNNABLE
    at java.lang.OutOfMemoryError.<init>(OutOfMemoryError.java:48)
    at java.util.Arrays.copyOfRange(Arrays.java:3664)
       Local Variable: char[]#32744
    at java.lang.String.<init>(String.java:207)
    at java.lang.StringBuilder.toString(StringBuilder.java:407)
    at java.util.UUID.toString(UUID.java:380)
    at com.steven.HeapOOMDemo.main(HeapOOMDemo.java:14)
       Local Variable: com.steven.HeapOOMDemo#1

栈内存溢出

1.代码示例

public class StackOOMDemo {
    private int length = 0;

    private void stackLeak() {
        this.length++;
        this.stackLeak();
    }

    public static void main(String[] args) {
        StackOOMDemo stackOOMDemo = new StackOOMDemo();
        try {
            stackOOMDemo.stackLeak();
        } catch (Exception e) {
            throw e;
        } finally {
            System.out.println("stack length:" + stackOOMDemo.length);
        }
    }
}

在stackLeak方法里定义一个局部变量字符串数组。

public class StackOOMDemo {
    private int length = 0;

    private void stackLeak() {
    	String [] strArr = {"one","two","three","four","five","six","steven","eight","nine","ten"};
        this.length++;
        this.stackLeak();
    }

    public static void main(String[] args) {
        StackOOMDemo stackOOMDemo = new StackOOMDemo();
        try {
            stackOOMDemo.stackLeak();
        } catch (Exception e) {
            throw e;
        } finally {
            System.out.println("stack length:" + stackOOMDemo.length);
        }
    }
}

2.设置栈最小内存

-Xss1024k

在这里插入图片描述

3.分别执行程序,输出如下结果

stack length:1889
Exception in thread "main" java.lang.StackOverflowError
	at com.steven.StackOOMDemo.stackLeak(StackOOMDemo.java:7)
	at com.steven.StackOOMDemo.stackLeak(StackOOMDemo.java:8)
	at com.steven.StackOOMDemo.stackLeak(StackOOMDemo.java:8)
	at com.steven.StackOOMDemo.stackLeak(StackOOMDemo.java:8)
	at com.steven.StackOOMDemo.stackLeak(StackOOMDemo.java:8)
	//......
stack length:1732
Exception in thread "main" java.lang.StackOverflowError
	at com.steven.StackOOMDemo.stackLeak(StackOOMDemo.java:7)
	at com.steven.StackOOMDemo.stackLeak(StackOOMDemo.java:8)
	at com.steven.StackOOMDemo.stackLeak(StackOOMDemo.java:8)
	at com.steven.StackOOMDemo.stackLeak(StackOOMDemo.java:8)
	at com.steven.StackOOMDemo.stackLeak(StackOOMDemo.java:8)
	//......

4.分析
从上述输出结果可以看到,相同配置,申明局部变量字符串数组的代码要少执行157次stackLeak()方法。这是因为,JVM在执行方法的时候,会为方法创建一个栈帧,栈帧存放方法的局部变量、操作数栈、返回值等信息,然后压入栈,而局部变量会占据一定的内存空间,且没有被释放,因此会导致执行方法的次数减少。

元空间内存溢出

1.代码示例

//1.字符串常量池
public class MethodAreaOOMDemo {
    public static void main(String[] args) {
        Set<String> stringSet = new HashSet<>();
        int count = 1;
        while (true) {
            //intern()是一个本地方法
            //如果字符串常量池存在需要加入的值,则直接返回字符串常量池中的引用
            //如果字符串常量池不存在需要加入的值,则将该字符串加入字符串常量池并返回引用
            stringSet.add(String.valueOf(count).intern());
        }
    }
}
//2.代理类
public class MethodAreaOOMDemo {
    public static void main(String[] args) {
        while(true) {
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(Greeting.class);
            enhancer.setUseCache(false);
            enhancer.setCallback(new MethodInterceptor() {
                @Override
                public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {

                    return null;
                }
            });
            //不断创建代理类,都会被加载进JVM内存
            enhancer.create();
        }
    }
}

2.设置元空间初始值和最大值

-XX:MetaspaceSize=2m -XX:MaxMetaspaceSize=2m

在这里插入图片描述

3.分别执行程序,输出如下结果

Error occurred during initialization of VM
java.lang.OutOfMemoryError: Metaspace
	at sun.misc.Launcher.<init>(Launcher.java:67)
	at sun.misc.Launcher.<clinit>(Launcher.java:53)
	at java.lang.ClassLoader.initSystemClassLoader(ClassLoader.java:1451)
	at java.lang.ClassLoader.getSystemClassLoader(ClassLoader.java:1436)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值