设置虚拟机启动参数

内存泄露和内存溢出的区别

概念区别

内存溢出(OutOfMemoryError): 指程序在申请内存时,没有足够的内存空间供其使用,出现OutOfMemoryError ,比如申请一个Integer但给它存了Long才能存下的数那就是内存溢出

内存泄露(Memory Leak): memory leak 指程序在申请内存后,无法释放已经申请的内存空间,一次内存泄露危害可以忽略,但内存泄露堆积后的结果很严重,无论多少内存,迟早会被占光,即不再被使用的对象内存不能被回收,就是内存泄露

Java堆溢出

介绍

Java堆的大小为20MB,不可扩展(将堆的最小值-Xms参数与最大值-Xmx参数设置为一样即可避免堆自动扩展),通过参数-XX:+HeapDumpOnOutOfMemoryError可以让虚拟机在出现内存溢出异常时Dump出当前的内存堆转储快照以便事后进行分析

Java堆的大小为20MB,不可扩展,设置堆的参数配置如下:

-Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError

Java堆内存溢出异常测试

import java.util.ArrayList;
import java.util.List;

/**
 * VM Args: -Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError
 * @author yanyugang
 * @description ${todo}
 * @date 2019-06-03 14:13
 */
public class HeapOOM {
    static class OOMObject{}

    public static void main(String[] args){
        List<OOMObject> list=new ArrayList<>();
        while (true){
            list.add(new OOMObject());
            System.out.println(list.size());
        }
    }
}
  • 输出如下
java.lang.OutOfMemoryError: Java heap space
Dumping heap to java_pid10936.hprof ...
Heap dump file created [13679366 bytes in 0.041 secs]

虚拟机栈和本地方法栈溢出

介绍

在Java虚拟机规范中描述了两种异常:

  1. 如果线程请求的栈深度大于虚拟机所允许的最大深度,将抛出StackOverflowError异常
  2. 如果虚拟机在扩展栈时无法申请到足够的内存空间,则抛出OutOfMemoryError异常

代码测试

Java栈的大小为128KB,设置栈的参数配置为:

-Xss128k

测试方法

  1. 使用-Xss参数减少栈内存容量。结果:抛出StackOverflowError异常,异常出现时输出的堆栈深度相应缩小
  2. 定义了大量的本地变量,增大此方法帧中本地变量表的长度。结果:抛出StackOverflowError异常时输出的堆栈深度相应缩小
/**
 * VM Args: -Xss128k
 * @author yanyugang
 * @description ${todo}
 * @date 2019-06-05 16:16
 */
public class JavaVMStackSOF {
    private int stackLength = 1;
    public void stackLeak(){
        stackLength++;
        stackLeak();
    }

    public static void main(String[] args){
        JavaVMStackSOF oom = new JavaVMStackSOF();
        try{
            oom.stackLeak();
        }catch (Throwable e){
            System.out.println("stack length:" + oom.stackLength);
            throw e;
        }
    }
}

  • 输出结果
stack length:980
Exception in thread "main" java.lang.StackOverflowError
	at demo.utils.JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:12)

方法区和运行时常量池溢出

在JDK1.6及之前的版本中,由于常量池分配在永久代内,我们可以通过-XX:PermSize和-XX:MaxPermSize限制方法区大小,从而间接限制其中常量池的容量

String.intern()是一个Native方法,它的作用是:如果字符串常量池中已经包含一个等于此String对象的字符串,则返回代表池中这个字符串的String对象;否则,将此String对象包含的字符串添加到常量池中,并且返回此String对象的引用

-XX:PermSize=10M -XX:MaxPermSize=10M
import java.util.ArrayList;
import java.util.List;

/**
 * VM Args: -XX:PermSize=10M -XX:MaxPermSize=10M
 * @author yanyugang
 * @description ${todo}
 * @date 2019-06-06 15:48
 * JDK6和JDK7运行的结果不一样
 * JDK6会报错:java.lang.OUtOfMemoryError:PermGen space
 * JDK7则不会报错
 */
public class RuntimeConstantPoolOOM {
    public static void main(String[] args) throws InterruptedException{
        // 使用List保持着常量池引用,避免Full GC回收常量池行为
        List<String> list = new ArrayList<>();
        // 10MB的PermSize在integer范围内足够产生OOM了
        int i =0;
        while (true){
            list.add(String.valueOf(i++).intern());
        }
    }
}

  • 借助CGLib使方法区出现的内存溢出异常
/**
 * VM Args: -XX:PermSize=1M -XX:MaxPermSize=1M
 * @author yanyugang
 * @description ${todo}
 * @date 2019-06-10 9:57
 */
public class JavaMethodAreaOOM {
    public static void main(String[] args){
        while (true){
            Enhancer enhancer=new Enhancer();
            enhancer.setSuperclass(OOMObject.class);
            enhancer.setUseCache(false);
            enhancer.setCallback(new MethodInterceptor() {
                @Override
                public Object intercept(Object obj, Method method, Object[] objects, MethodProxy proxy) throws Throwable{
                    return proxy.invoke(obj,objects);
                }
            });
            enhancer.create();
        }
    }

    static class OOMObject{

    }

}

本机直接内存溢出

DirectMemory容量可以通过 -XX:MaxDirectMemory指定,如果不指定,则默认与Java堆最大值(-Xmx指定)一样

/**
 * VM Args: -Xmx20M -XX:MaxDirectMemorySize=10M
 *
 * @author yanyugang
 * @description ${todo}
 * @date 2019-06-10 10:32
 */
public class DirectMemoryOOM {
    private static final int _1MB=1024 * 1024;

    public static void main(String[] args) throws Exception{
        Field unsafeField =Unsafe.class.getDeclaredFields()[0];
        unsafeField.setAccessible(true);

        Unsafe unsafe=(Unsafe) unsafeField.get(null);
        while (true){
            unsafe.allocateMemory(_1MB);
        }
    }
}

  • 运行结果
Exception in thread "main" java.lang.OutOfMemoryError
	at sun.misc.Unsafe.allocateMemory(Native Method)
	at demo.utils.DirectMemoryOOM.main(DirectMemoryOOM.java:23)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值