Java内存模型

java的内存区域划分

  根据《Java虚拟机规范》的规定,运行时数据区通常包括这几个部分:

    程序计数器(Program Counter Register)

    虚拟机栈(VM Stack)

    本地方法栈(Native Method Stack)

    方法区(Method Area)

    堆(Heap)

  如下图: 
  

 

  看到这个模型,使用堆和栈划分内存区域还是很有道理的,java虚拟机规范将方法区描述为堆的一个逻辑部分

  这种模型和我们粗略的内存模型的对应关系为:

    堆=堆+方法区  

    栈=虚拟机栈+本地方法栈


  • 程序计数器

    线程隔离,即每个线程都有自己的程序计数器,并且互不影响。分为两种情况,当线程正在执行的是一个java方法,它的作用是作为字节码的行号指示器,指向下一条需要执行的指令。当线程正在执行的是一个Native方法,那么它的值为空(Undefined)。java虚拟机规范中唯一没有定义OOM(OutOfMemoryError)异常的内存区域。

  • java虚拟机栈

    线程隔离,生命周期与线程相同。它描述的是java方法执行的内存模型,每一个java方法执行的时候都会产生一个栈帧(Stack Frame),用于存储局部变量表、操作数栈、动态链接、方法出口等信息。当进入一个方法时,栈帧的大小是编译器确定的,运行时不会改变其大小。当虚拟机栈不可扩展的时候,可能抛出StackOverflowError异常,反之,可能抛出OOM异常

  • 本地方法栈

    与java虚拟机栈功能一致,只不过本地方法栈是针对Native方法的。同样在虚拟机规范中定义了StackOverflowErrorOOM两种异常。

  • Java堆

    Java堆是被所有线程共享的一块内存区域,在虚拟机启动时创建。此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存。
    Java虚拟机规范中的描述为:所有的对象实例以及数组都要在堆上分配。
    只要是用到new关键字创建的对象都会进入到这个区域,包括对象,数组
    堆还能进一步划分,比如按照内存回收的角度来看,堆可以进一步划分为新生代(Eden+Survivor)老年代。按照内存分配的角度来看,堆可以进一步划分为多个线程私有的分配缓存区,即TLAB(Thread Local Allocation Buffer)。这种进一步的划分是为了更高效地回收和分配内存。java虚拟机规范中定义了OOM异常

  • 方法区

    这个区域很容易引发误会,很多人会以为方法区会存储方法中的局部变量,然而并不是。方法区与Java堆一样,是各个线程共享的内存区域,这个区域用于存储被加载的类的信息,常量,静态变量以及即时编译器编译后的代码等数据。Java虚拟机把方法区描述为堆得一个逻辑部分。虚拟机规范中定义了OOM异常。还需要注意的一点是,HotSpot虚拟机中的方法区被很多人称之为“永生代”,这是因为HotSpot的开发团队将分代收集算法运用到了方法区,但是这并不是必须的。

posted @ 2019-06-26 15:41  CoderZZZ  阅读(139)  评论(0编辑  收藏  举报