zoukankan      html  css  js  c++  java
  • Java 虚拟机的内存溢出

    在Java虚拟机规范的描述中,除了程序计数器外,虚拟机内存的其他几个运行时区域都有发生 OutOfMemoryError 异常的可能。

    在Eclipse中进行JVM参数设置

    可以直接通过上方菜单栏的 Run 下的 Run Configurations... 或者 Debug Configurations... 选项进行设置。

    双击 Java Application 会生成一个新的配置卡。

    在新的配置卡中可配置名称Name,Main里面的Project配置项目名,Main class配置main方法所在的类。

    (如果是从main方法里面右键打开的Run As-->Run Configurations...或者Debug As-->Debug Configurations...,这几项会自己生成)

    Arguments下面的VM arguments 里面配置虚拟机参数。

     参数解释: 

    1,堆是存储对象实例的,创建的对象都是在堆中进行内存分配的;设置堆的大小:-Xmx20M(最大值) ,-Xms20M(最小值),其中-Xmn设置年轻代大小。

    2,栈是存储局部变量,操作栈,动态链接,方法出口(都在栈桢中) 的地方,调用方法时,会创建栈桢;设置栈的大小:-Xss128K。

    3,方法区是存放Class的相关信息,如类名,访问修饰符,常量池,字段描述,方法描述等。此外运行时常量池是属于方法区的,即存放常量,静态常量等;设置方法区大小,-XX:PermSize=10M和-XX:MaxPermSize=10M。

    4,本地直接内存;设置本地直接内存大小:-XX:MaxDirectMemorySize(默认与-Xmx的值一样)。

    堆内存溢出

    Java堆用于存储对象实例,只要不断的创建对象,并且保证 GC Roots 到对象之间有可达路径来避免垃圾回收机制清除这些对象,那么在对象数量到达最大堆的容量限制后就会产生内存溢出异常。

    参数设置:-verbose:gc -Xms20M -Xmx20M -XX:+HeapDumpOnOutOfMemoryError

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

    代码:

    package jvm;
    
    import java.util.ArrayList;
    import java.util.List;
    
    public class HeapOOM {
    
        static class OOMObject {
        }
    
        public static void main(String[] args) {
            List<OOMObject> list = new ArrayList<>();
    
            while (true) {
                list.add(new OOMObject());
            }
    
        }
    
    }

    运行结果:

    栈内存溢出

    在HotSpot虚拟机中并不区分虚拟机栈和本地方法栈,所以 -Xoss 参数无效,栈容量只由 -Xss 参数控制。

    参数设置:-Xss128k

    代码:

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

    运行结果:

    方法区内存溢出

    参数设置:-XX:PermSize=10M -XX:MaxPermSize=10M

    注意:JDK8中用 MetaspaceSize 代替 PermSize,因此将 -XX:PermSize=10M -XX:MaxPermSize=10M 修改为 -XX:MetaspaceSize=10M -XX:MaxMetaspaceSize=10M

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

    代码一:

    package jvm;
    
    import java.util.ArrayList;
    import java.util.List;
    
    public class RuntimeConstantPoolOOM {
    
        public static void main(String[] args) {
            // 使用List保持常量池引用,避免 Full GC 回收常量池行为
            List<String> list = new ArrayList<>();
            // 10MB的 PermSize在Integer范围内足够产生OOM了
            int i = 0;
            while (true) {
                list.add(String.valueOf(i++).intern());
            }
    
        }
    
    }

    以上代码在JDK1.6及之前的版本下,由于常量池分配在永久带内,运行时常量池溢出,使用JDK1.7以及更高版本运行这段程序不会得到相同结果,while循环将一直进行下去。因为1.7及更高版本的常量池值只保存了引用。

    代码二:

    package jvm;
    
    public class RuntimeConstantPoolOOM {
    
        public static void main(String[] args) {
            
            String str1 = new StringBuilder("计算机").append("软件").toString();
            System.out.println(str1.intern() == str1);
            
            String str2 = new StringBuilder("ja").append("va").toString();
            System.out.println(str2.intern() == str2);
    
        }
    
    }

    运行结果:

    结果分析:

    JDK1.6会得到两个false。

    在JDK1.6中,intern() 方法会把首次遇到的字符串实例复制到永久代中,返回的也是永久带中这个字符串实例的引用。而 StringBuilder 创建的字符串实例在堆上,所以不是同一个引用,返回 false。

    JDK1.7中会得到一个true和一个false。

    在JDK1.7中,intern() 方法不会再复制实例,只在常量池中记录首次出现的实例引用,该引用指向的是堆中的实例,这个实例就是 StringBuilder 创建的那个字符串实例,所以是同一个引用,返回true。

    返回false是因为 “java” 这个字符串在中StringBuilder之前已经出现过,字符串常量池中已经有它的引用了,而 StringBuilder 又重新创建了一个“java”字符串实例,所以str2中保存的是新创建的实例的引用,而str2.intern() 返回的是旧的实例的引用,所以不是同一个引用,返回false。

    代码三:

    package jvm;
    
    import java.lang.reflect.Method;
    
    import net.sf.cglib.proxy.Enhancer;
    import net.sf.cglib.proxy.MethodInterceptor;
    import net.sf.cglib.proxy.MethodProxy;
    
    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[] args, MethodProxy proxy) throws Throwable {
                        return proxy.invokeSuper(obj, args);
                    }
                });
    
                enhancer.create();
    
            }
    
        }
    
        static class OOmObject {
        }
    
    }

    以上代码使用使用CGLib使方法区出现内存溢出异常。使用到下面的两个jar包。

    JDK8运行结果:

    本机直接内存溢出

    参数设置:-Xmx20M  -XX:MaxDirectMemorySize=10M

    直接内存容量可通过 MaxDirectMemorySize 指定,如果不指定,则默认和Java堆最大值一样(-Xmx)。

    代码:

    package jvm;
    
    import java.lang.reflect.Field;
    
    import sun.misc.Unsafe;
    
    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);
            }
        }
    
    }

    运行结果:

  • 相关阅读:
    2.Android之按钮Button和编辑框EditText学习
    《DSP using MATLAB》Problem 3.8
    《DSP using MATLAB》Problem 3.7
    《DSP using MATLAB》Problem 3.6
    《DSP using MATLAB》Problem 3.5
    《DSP using MATLAB》Problem 3.4
    《DSP using MATLAB》Problem 3.3
    《DSP using MATLAB》Problem 3.2
    《DSP using MATLAB》Problem 3.1
    《DSP using MATLAB》Problem 2.20
  • 原文地址:https://www.cnblogs.com/wbxk/p/7111558.html
Copyright © 2011-2022 走看看