JMM

2020-05-11  本文已影响0人  Sandy_678f

Java Memory Model ,JMM Java内存模型
(图片来源于网络,侵删。)


image.png
  1. 程序计数器
  2. Java虚拟机栈
  3. 本地方法栈
  4. 方法区

程序计数器,Java虚拟机栈,本地方法栈是线程私有的。
方法区,堆是线程共享的。

  1. 程序计数器
这块区域是虚拟机规范中唯一没有OutOfMemory错误的区域
  1. Java虚拟机栈
    描述的是Java方法执行的内存模型:每个方法执行的同时会创建一个栈帧。
    栈帧存储了方法的局部变量表、操作数栈、动态连接和方法返回地址等信息。
1)线程请求的栈深度大于虚拟机允许的栈深度,将抛出StackOverflowError
2)虚拟机栈空间可以动态扩展,当动态扩展无法申请到足够的空间时,则抛出OutOfMemory异常
  1. 本地方法栈
    本地方法栈与虚拟机栈发挥的作用十分相似,区别是虚拟机栈执行的是Java方法(也就是字节码)服务,而本地方法栈则为虚拟机使用到的native方法服务,可能底层调用的c或者c++,我们打开jdk安装目录可以看到也有很多用c编写的文件,可能就是native方法所调用的c代码。


  2. 堆是java虚拟机管理内存最大的一块内存区域,因为堆存放的对象是线程共享的,所以多线程的时候也需要同步机制
    它是所有线程共享的,它的目的是存放对象实例。同时它也是GC所管理的主要区域,因此常被称为GC堆。当前主流的虚拟机如HotPot都能按扩展实现(通过设置 -Xmx和-Xms)。

如果堆中没有内存内存完成实例分配,而且堆无法扩展将报OOM错误(OutOfMemoryError)
  1. 方法区
    用于存储已被虚拟机加载的类信息、常量、静态变量,如static修饰的变量加载类的时候就被加载到方法区中。
运行时常量池
是方法区的一部分,class文件除了有类的字段、接口、方法等描述信息之外,还有常量池用于存放编译期间生成的各种字面量和符号引用。

溢出的两个基本例子:

public class MemErrorTest {

    public static void hi(){
        hi();
    }

    public static void main(String[] args) {
        try{
            List<Object> list = new ArrayList<Object>();
            for(;;){
                //创建对象速度可能高于JVM
                list.add(new Object());
            }
        }catch (OutOfMemoryError e){
            e.printStackTrace();
        }

        try{
            //递归造成StackOverflowError 这边因为每运行一个方法将创建一个栈帧
            hi();
        }catch (StackOverflowError e){
            e.printStackTrace();
        }
    }
}

运行结果:

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:265)
    at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:239)
    at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:231)
    at java.util.ArrayList.add(ArrayList.java:462)
    at menerror.MemErrorTest.main(MemErrorTest.java:24)
java.lang.StackOverflowError
    at menerror.MemErrorTest.hi(MemErrorTest.java:16)
    at menerror.MemErrorTest.hi(MemErrorTest.java:16)
    at menerror.MemErrorTest.hi(MemErrorTest.java:16)
……
上一篇下一篇

猜你喜欢

热点阅读