Java内存区域与内存溢出异常

Java虚拟机运行时数据区

09114939_mjZk.png

程序计数器

程序计数器可以看作是当前线程所执行的字节码的行号指示器
线程私有

异常:
唯一一个java虚拟机规范中没有规定任何OutOfMemoryError情况的区域

Java虚拟机栈

线程私有,生命周期和线程相同
虚拟机栈描述的是Java方法执行的内存模型:每个方法在执行的同时会创建一个栈帧用于存储局部变量表、操作数栈、动态链接、方法出口等信息。局部变量表存放了编译期可知的各种基本数据类型、对象引用。

异常:
线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverFlowError异常
如果虚拟机栈可以动态扩展,如果扩展无法申请到足够的内存,就会抛出OOM
/**
 * 虚拟栈递归调用栈溢出(StackOverFlowError)
 * VM Args:-Xss512k
 */
public class JavaVMStackSOF {
    private int stackLenqth = 1;

    public void stackLeek() {
        stackLenqth++;
        //递归调用
        stackLeek();
    }

    public static void main(String[] args) {
        JavaVMStackSOF stackSOF = new JavaVMStackSOF();
        stackSOF.stackLeek();
    }
}
//结果
Exception in thread "main" java.lang.StackOverflowError
	at outofmemory.JavaVMStackSOF.stackLeek(JavaVMStackSOF.java:11)
/**
 * 创建线程导致OOM
 * VM Args: -Xss2M
 */
public class JavaVMStackOOM {
    private void  dontStop(){
        while (true){

        }
    }

    public void stackLeakByThread(){
        while (true){
            Thread thread = new Thread(new Runnable() {
                public void run() {
                    dontStop();
                }
            });
            thread.start();
        }
    }

    public static void main(String[] args) {
        JavaVMStackOOM stackOOM = new JavaVMStackOOM();
        stackOOM.stackLeakByThread();

    }
}
//结果
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space

本地方法栈

所有线程共享
本地方法栈和Java虚拟栈相似,Java虚拟机栈为虚拟机执行Java方法(字节码)服务,本地方法栈为虚拟机
用到的native方法服务。
HotSpot虚拟机将虚拟机栈和本地方法栈合二为一

Java堆

所有的对象实例和数组都要在堆上分配
Java堆是垃圾器管理的主要区域

异常:
堆中没有内存完成实例分配,并且堆无法在扩展的时,就会抛出OOM
/**
 * 堆内存溢出
 * VM Args: -Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError
 */
public class HeapOOM {
    static class OOMObject {
    }

    public static void main(String[] args) {
        List<OOMObject> list = new ArrayList<OOMObject>();
        while (true) {//循环创建对象
            list.add(new OOMObject());
        }
    }
}
//运行结果
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space

方法区

所有线程共享
用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据

异常:
方法区无法满足内存分配需求时,就会抛出OOM

运行时常量池

方法区的一部分
用于存放编译期生成的各种字面量和符号引用
Java并不要求常量一定要是编译期才能产生,运行期间也可能将新的常量放入池中,比如String类的intern()方法

异常:
运行时常量池作为方法区的一部分,自然收到方法去内存的限制,常量池无法申请到内存抛出OOM
/**
 * 运行是常量池溢出
 * VM Args: -XX:PermSize=10M -XX:MaxPermSize=10M
 */
public class RuntimeConstantPoolOOM {
    public static void main(String[] args) {
        List<String> stringList = new ArrayList<String>();
        int i = 1;
        while (true){
            stringList.add(String.valueOf(i++));
        }
    }
}
//结果
Java HotSpot(TM) 64-Bit Server VM warning: ignoring option PermSize=10M; 
support was removed in 8.0
Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=10M; 
support was removed in 8.0
// 分析
我使用的时jdk8.0发生如上错误,这个说明永久代已经在java8.0中被移除,被元空间替代。
关于为啥要移除替代本篇不累赘。如果使用的jdk8.0一下版本则会出现OOM:PermGen space
这样可以证明常量池属于方法区
//VM Args:-XX:MaxMetaspaceSize=2M(这样设置元空间大小 )

直接内存

直接内存不是虚拟机运行时数据区的一部分,也不是Java虚拟机规范中定义的内存区域
NIO可以使用Native函数库直接分配堆外内存


异常:
本机内存不足抛出OOM

 参考资料:《深入理解Java虚拟机》

转载于:https://my.oschina.net/u/2361475/blog/600000

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值