《深入理解 Java 虚拟机》学习笔记2

《深入理解 Java 虚拟机》学习笔记2

第2章 Java 内存区域与内存溢出异常

2.1 概述

2.2.1 程序计数器

  1. 程序计数器(Program Counter Register)
  2. java 虚拟机的多线程是通过线程轮流切换并分配处理器执行时间来实现的,在任何一个确定额时刻,一个处理器(对于多核来说是一个内核)都只会执行一条线程中的指令。因此,为了线程切换后可以恢复到正确的执行位置,每条线程需要一个独立的程序计数器,各条线程之间的计数器互不影响,独立存储。
  3. 如果线程正在执行的是一个 Java 方法,则计数器记录的是正在执行的虚拟机字节码指向的地址;如果执行的是 Native 方法,这个计数器为空(Undefined)。

2.2.2 Java 虚拟机栈

  1. Java 虚拟机栈(Java Virtual Machine Stack)是线程私有的,它的生命周期与线程相同。
  2. Java 虚拟机栈描述的是 Java 方法执行的内存模型:每个方法在执行的同时都会创建一个栈帧(Stack Frame)用于存储局部变量表,操作数栈,动态链接,方法出口等信息。每一个方法从调用到执行完毕的过程,对应着一个栈帧咋即虚拟机栈中入栈到出栈的过程。
  3. Java 中的『栈』往往指的就是虚拟机栈,或者说是『虚拟机栈中的局部变量表』。局部变量表包含:基本数据类型(boolean, byte, char, short, int, float, long, double) + 对象引用(reference)+ returnAddress
  4. 局部变量表所需的空间在编译期间完成,当进入一个方法时,这个空间往往是一定的。
  5. 在 Java 虚拟机规范中,在这个区域定义了两种异常状况:
    1. 如果线程请求的栈深度大于虚拟机所允许的深度,将抛出 StackOverflowError 异常。
    2. 如果虚拟机栈可以动态扩展,如果扩展时无法申请到足够的内存,抛出 OutOfMemoryError 异常。

2.2.3 本地方法栈

  1. 本地方法栈(Java Native Method Stack)类似虚拟机栈,不过虚拟机栈是为 Java 方法服务,本地方法栈为 Native 方法服务。

2.2.4 Java 堆

  1. 对于大多数应用来说,Java 堆(Java Heap)是 Java 虚拟机所管理的内存中最大的一块。Java 堆是被所有线程共享的一块内存区域,在虚拟机启动时创建。此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都是在这里分配的内存。
  2. Java 堆是垃圾收集器管理的主要区域,因此很多时候也被称为『GC堆(Garbage Collected Heap)』
  3. Java 堆可以是物理上不连续的,只要逻辑上连续即可,就像我们的磁盘一样。如果堆满了,无法继续进行扩展,会报错 OutOfMemoryError 异常。

2.2.5 方法区

  1. 方法区(Method Area)与 Java 一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码等数据。

2.2.6 运行时常量池

  1. 运行时常量池(Runtime Constant Pool)是方法区的一部分。用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后进入方法区的运行时常量池中存放。
  2. Java 虚拟机对 Class 文件的每一部分的格式都有严格的规定,每一个字节用于存储哪种数据都必须符合规范上的要求才会被虚拟机认可,装载和执行。
  3. 运行时常量池相对于 Class 文件常量池的另外一个重要特征就是具备动态性Java 语言并不要求常量一定只有编译期才能产生,运行期间也可能将新的常量放入池。这种特性被开发人员用的较多的是 String 的 intern() 方法。

2.2.7 直接内存

  1. 直接内存(Direct Memory)并不是虚拟机运行时数据区的一部分,也不是 Java 虚拟机规范中定义的内存区域。在 JDK1.4 中引入 NIO(New Input/Output)类,引入一种基于通道(Channel)与缓冲区(Buffer)的 I/O 方式,它可以使用 Native 函数库直接分配堆外内存,然后通过一个存储在 Java 堆中的 DirectByteBuffer 对象作为这块内存的引用进行操作。

2.3 HotSpot 虚拟机对象探秘

2.3.1 对象的创建

  1. 虚拟机遇到一条 new 指令时,首先将去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已经被加载,解析和初始化过。如果没有,必须先执行 相应类的加载过程
  2. 类加载检查通过后,虚拟机为新生对象分配内存。对象所需内存的大小在类加载完后可以完全确定,为对象分配空间的任务等同于把一块确定大小的内存从 Java 堆中划分出来。
    原文作者:java虚拟机
    原文地址: https://blog.csdn.net/wumingdezu/article/details/52903216
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞