zoukankan      html  css  js  c++  java
  • Java内存区域与内存溢出异常

        先贴上一段参数设置

    JAVA_OPTS=" $JAVA_OPTS -Dspring.profiles.active=test -DLOG_DIR=/home/work/logs 
    -Xms2048m -Xmx2048m -Xss1m -XX:NewSize=512m -XX:MaxNewSize=512m -XX:PermSize=128m
    -XX:MaxPermSize=512m -XX:SurvivorRatio=6 -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -Dfile.encoding=UTF-8
    "

        很多时候,将代码部署到服务器,都会对JAVA_OPTS进行一些操作,大多数情况对主要两个知道是干嘛的,其实的哪copy的算哪的。

        所以,看了点资料,想写点东西。

        Java虚拟机运行时数据区,主要包括以下部分:方法区、堆,它们是线程共用的部分;虚拟机栈、本地方法栈、程序计数器。下面我

    大概讲讲如上几个部分。

    1. 程序计数器。
        线程自己的数据区,用以记录当前线程所执行的字节码的行号指示器,主要用于在线程切换过程中,保证切换后能够恢复到正确的执行位置,此区域是惟一一个在Java虚拟机规范中没有规定任何OOM情况的区域。
    
    2. Java虚拟机栈。
        线程独自拥有,生命周期与线程相同。异常状况,若线程请求栈深度大于虚拟机所允许,则StackOverflowError,若虚拟机栈可动态扩展,在扩展无法申请得到足够内存则OOM。
    
    3. 本地方法栈。
        相对于虚拟机栈为虚拟机执行Java方法服务,本地方法栈则为虚拟机使到的Native方法服务。为线程私有空间。
    
    4. Java堆。
        线程共享区域,在虚拟机启动时创建,为GC管理的主要区域。可设置为固定或者可扩展大小,由-Xmx和-Xms控制,设置成一样即为固定。若无空间分配实例,且无法扩展,则OOM。
    
    5. 方法区。
        线程共享,用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等。此区域也要GC,主要是对常量池回收和对类型的卸载,会有OOM异常。(运行时常量池,用于存放编译期生成的各种字面量和符号引用,在类加载后存储,运行期间也可能将新的常量放入池中,如String类的intern()方法)。

      来几个简单实例。

      Java堆溢出:

    package com.wdm.mem;
    
    import java.util.ArrayList;
    import java.util.List;
    
    /*
     * VM: -Xms1m -Xmx1m -XX:+HeapDumpOnOutOfMemoryError
     */
    public class HeapOOM {
    
        static class OOMObejct {
        }
    
        public static void main(String[] args) {
            List<OOMObejct> list = new ArrayList<>();
            System.out.println("start");
            int i = 0;
            while (true) {
                i++;
                if (i % 10000 == 0) {
                    System.out.println(i);
                }
                list.add(new OOMObejct());
            }
        }
    }

    输出如下:

    start
    10000
    20000
    30000
    40000
    java.lang.OutOfMemoryError: Java heap space
    Dumping heap to java_pid21966.hprof ...
    Heap dump file created [2399791 bytes in 0.014 secs]
    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:261)
        at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:235)
        at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:227)
        at java.util.ArrayList.add(ArrayList.java:458)
        at com.wdm.mem.HeapOOM.main(HeapOOM.java:23)

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

       

    package com.wdm.mem;
    
    /*
     * VM: -Xss160k
     */
    public class JavaVMStackSOF {
    
        private int stackLen = 1;
    
        public void stackLeak() {
            stackLen++;
            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.stackLen);
                throw e;
            }
        }
    }
    
    
    // 输出:
    stack length:771Exception in thread
    "main" java.lang.StackOverflowError at com.wdm.mem.JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:11) at com.wdm.mem.JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:12) at com.wdm.mem.JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:12) at com.wdm.mem.JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:12) // 设置小于160k时报错 The stack size specified is too small, Specify at least 160k Error: Could not create the Java Virtual Machine. Error: A fatal exception has occurred. Program will exit.

    运行时常量池溢出:

    Java HotSpot(TM) 64-Bit Server VM warning: ignoring option PermSize=1M; support was removed in 8.0
    Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=1M; support was removed in 8.0
    
    
    package com.wdm.mem;
    
    import java.util.List;
    import java.util.ArrayList;
    
    /*
     * VM: -XX:PermSize=10M -XX:MaxPermSize=10M
     */
    public class RuntimeConsPoolOOM {
    
        public static void main(String[] args) {
            List<String> list = new ArrayList<>();
            int i = 0;
            while (true) {
                list.add(String.valueOf(i++).intern());
            }
        }
    }
    
    
    JDK8已经不用这两个参数了:可以看这个http://www.cnblogs.com/paddix/p/5309550.html

    PS:此文由看《深入理解Java虚拟机:JVM高级特性与最佳实践》而来

  • 相关阅读:
    - 错误笔记
    只是一个没有人知道的蒟蒻
    省选前模板复习
    数学知识小结#1
    写在NOIP2018后
    Atcoder&CodeForces杂题11.7
    Atcoder&CodeForces杂题11.6
    [NOIP11.1模拟赛]补番报告
    [JZOJ5281]钦点题解--瞎搞+链表
    [JZOJ5280]膜法师题解--思维+前缀和
  • 原文地址:https://www.cnblogs.com/hawk-whu/p/6731260.html
Copyright © 2011-2022 走看看