图片描述

这里主要以HotSpot虚拟机作为描述对象

一、程序计数器(Program Counter Register)

  1. 程序计数器是一块较小的内存空间,是当期线程执行字节码的行号指示器。
    字节码通过改变这个计数器的值来确定下一个需要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖计数器来完成。

  2. java虚拟机的多线程是通过线程的轮流切换并分配处理器执行时间的方式来实现的,在任何一个确定的时刻一个处理器都只会执行一条线程的指令。为了线程切换后恢复到正确的执行位置,每条线程都需要有一个独立的程序计数器。所以这块内存是“线程私有”的内存。

  3. 该区域是虚拟机规范中为一个没有规定任何OutOfMemoryError情况的区域。

二、java虚拟机栈(Java Virtual Machine Stacks)

  1. Java虚拟机栈是线程私有的。

  2. 生命周期与线程相同。

  3. 描述的是java方法执行的内存模型:每一个方法执行的同时都会创建一个栈帧(Starck Frame)用于存储局部变量表、操作数栈、动态链接等信息。每个方法的开始调用到执行完成的过程都对应着一个栈帧在虚拟机栈中入栈到出栈的过程

  4. 局部变量表中存放了编译期可知的各种基本数据类型(boolean、byte、char、short、int、float、long、double)以及对象引用(reference类型,它不是对象本身,可能是一个指向:对象起始地址的引用指针、对象句柄)和returnAddress类型(指向一条字节码指令的地址)。

  5. 虚拟机规范中对这块区域规定了两种异常状况:
    1> 如果线程请求的栈深度大于虚拟机所允许的深度将抛出StackOverflowError异常
    2> 如果虚拟机栈可以动态扩展,而扩展时无法申请到足够的内存,就会抛出OutOfMemoryError异常

三、本地方法栈(native Method Stack)

  1. 与虚拟机栈的作用非常相识,区别就是:虚拟机栈为虚拟机执行java方法服务,而本地方法栈为虚拟机使用到的native方法服务。SunHotSpot虚拟机把虚拟机栈和本地方法栈合并了。

  2. 与虚拟机栈一样本地方法栈也会抛出StackOverflowError和OutOfMemoryError异常

  3. 所以本地方法栈也是线程私有的

四、Java 堆(Java Heap)

从内存回收的角度来看由于现在的垃圾收集器都是采用分代收集的算法,所以这块区域又可细分为新生代和老年代,默认情况新生代又可分为一个Eden空间和两个Survivor空间。从内存分配的角度来看,线程共享的java heap可能需要划分出多个线程私有的分配缓冲区(Thread Local Allocation Buffer, TLAB)

  1. java堆是虚拟机所管理的内存中最大的一块区域,也是垃圾收集器管理的主要区域。

  2. 虚拟机启动时创建,所有线程共享。

  3. 唯一目的就是用来存放对象实例。所有的对象实例以及数组都要在堆上分配内存

  4. 可以通过-Xmx和-Xms来控制heap的可扩展性。

  5. 如果heap中没有足够的内存完成实例的分配,并且也无法再扩展时将会抛出OutOfMemoryError异常

五、方法区(Method Area)

对于HotSpot虚拟机上开发者也把这块区域成为“永久代”(Permanent Generation)。两者本质上并不等价,只是为了垃圾收集器可以像管理 Java 堆一样去管理这部分区域而把GC分代收集扩展到了这里。

  1. 线程共享的区域。

  2. 用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译(Just In Time,JIT编译器)后的代码等数据。

  3. 可以通过-XX:PermSize 和 -XX:MaxPermSize来设置这块区域的可扩展性

  4. 可能会抛出OutOfMemoryErrory

六、运行时常量池(Runtime Constant Pool)

这块区域是方法区的一部分。用于存放编译期生成的各种字面量和符号引用,这部分内容再类加载后存入方法区的运行时常量池中。既然是方法区的一部分,自然受到方法区内存的限制,当常量池无法申请到内存时会抛出OutOfMemoryErrory


idgq
575 声望13 粉丝