深入理解JAVA虚拟机-学习笔记(java内存区域)

深入理解JAVA虚拟机-学习笔记(java内存区域)

程序计数器

Program Counter Register:是一个较小的内存空间,可以看做是当前线程所执行的字节码的行号指示器。字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令。(分支、循环、异常等功能都需要这个计数器来完成)。
java虚拟机的多线程都是通过线程轮流切换并分配处理执行时间的方式来实现的(时间片),在任何一个时刻,一个处理器只能执行一条线程中的指令。因此。为了线程切换后可以恢复到正确的位置(上下文切换),每条线程都需要一个独立的程序计数器,独立存储。称为“线程私有的内存”。
如果线程 执行的是一个java方法,那计数器记录的是正在执行的虚拟机字节码指定的地址。
如果执行的是native方法,这个计数器则为空。

程序计数器是唯一一个没有规定OutOfMemoryError的区域

java虚拟机栈

虚拟机栈也是线程私有的。他的生命周期和线程一样。
虚拟机栈描述的是java方法执行的内存模型:每个方法在执行的同时都会创建一个栈帧用于存储局部变量表、操作数栈、动态链接、方法出口等。每一个方法的调用到执行完成,就对应一个栈帧在虚拟机栈中入栈到出栈的过程。

局部变量表:存放编译期可知的各种基本数据类型(boolean、byte、char、short、int、float、long、double)、对象引用。其中64位长度的long和double占用2个局部变量表。其余都是一个。

局部变量表所需要的内存在编译期完成分配,且后续不可变。如果线程请求的栈深度大于虚拟机允许的深度,就会StackOverflowError。

本地方法栈

本地方法栈和虚拟机栈区别就是虚拟机栈为虚拟机执行java(字节码)方法,本地方法栈则为虚拟机使用到的native方法服务。

java堆

堆是虚拟机中内存最大的一块。是所有线程共享的区域,在虚拟机启动的时创建这个区域的唯一目就是存放对象实例几乎所有对象都在这里分配内存。(所有对象实例和数组都要在堆上分配)

方法区

方法区也是线程共享的区域。存储已被虚拟机加载的类信息、常量、静态变量。

运行时常量池

运行时常量池也是方法区的一部分。Class文件除了有类的版本、字段、方法、接口等描述信息外。还有一项信息:常量池。用于存放编译期生生成的各种字面量和符号引用。这部分内容将在类加载后进入方法区的运行时常量池。

对象的创建

  1. 虚拟机遇到一条new指令后,先执行响应的类加载过程

  2. 类加载检查通过后,为新生代对象分配内存。所需大小在类加载完成时候就完全确定。分配内存的方法“指针碰撞:堆中内存规整,用的内存在一边,空闲的在另一边,中间放一个指针作为分界点的指示器,”分配内存就是把指针往空闲区域挪动所需大小的距离。
    空闲列表:堆内存是相互交错的。虚拟机就必须维护一个列表(那一块是可用的,那一块是占用的),分配就是从列表中找一块足够大的空间划分出来

  3. 分配完内存,虚拟机需要将分配到的内存空间全部初始化为零。

  4. 设置对象头等信息