(2)JVM——Java 虚拟机运行时数据区域讲解

本人个人博客网站,欢迎访问:学教府

一、简述

  1. 介绍:如果有了解 C/C++,以及 Java 语言的朋友,肯定知道它们之间最大的差别的就是对于内存的回收。用 C/C++ 时,自己创建的对象得自己回收内存,而 Java 则是因为其自带的垃圾收集器,将开发者解放出来。犹记得当初大学学 C 语言,讲到指针的那一节,就感觉指针是无所不能,各种灵活,不过如果用不好就容易飘。本篇博客主要简单介绍一下 Java 虚拟对于内存的划分,以及大概作用。

二、内存运行时数据区

Java虚拟机运行时数据区

  1. 这张图片展示的就是 JVM 对于内存的经典划分,主要分为了程序计数器虚拟机栈本地方法栈方法区,同时还有运行时常量池直接内存

  2. 程序计数器

    • 线程私有(每条线程独立有一个),可以看成当前线程所执行的字节码的行号指示器。
    • 如果线程正在执行的是一个 Java 方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址;如果正在执行的是本地方法,这个计数器值则应为空。
    • 此内存区域是唯一没有 OutOfMemoryError 情况的区域
  3. 虚拟机栈: 通俗的讲,一个线程有一个虚拟机栈,这个栈就是一个中间容器,帮助线程在执行过程中完成各项处理。其中栈里面的一个基础单位就是栈帧,一个栈帧可以简单的对应一个方法,在进入方法后会有局部变量等数据,此时就创建一个栈帧来保存这些信息(比如局部变量表、操作数栈、动态连接、方法出口等信息)。栈是先进后出的数据结构。虚拟机栈特点如下:

    • 线程私有,生命周期与线程相同
    • 一个方法的执行对应一个栈帧的入栈和出栈过程
    • 局部变量表存放 8 种基本数据类型、对象引用和 returnAddress 类型
    • long 和 double 占用两个变量槽,其他类型是只占一个
    • 两类异常状况:
      ① 如果线程请求的栈深度大于虚拟机所允许的深度,将抛出 StackOverFlowError 异常
      ② 如果 Java 虚拟机栈容量可以动态扩展(HotSpot 不可以),当栈扩展时无法申请到足够的内存会抛出 OutOfMemoryError 异常
  4. 本地方法栈:本地方法栈和虚拟机栈基本一样,区别是 虚拟机栈为虚拟机执行 Java 方法(字节码)服务,而本地方法栈是为虚拟机使用到的本地方法服务 。异常和虚拟机栈的一致。本地方法解释可以查看——详解native方法的使用

  5. Java 堆:堆是虚拟机管理的内存中最大的一块,这块地方存放了 Java 中几乎所有的对象实例(有容乃大)。因为这块地方大,并且发生的故事多,所以内存的回收(垃圾收集器)都发生在这儿,因此也被叫为 “GC堆”。有四处特点如下:

    • 虽然堆是线程共享的,但是在共享的地方也会为线程划分私有的分配缓冲区
    • Java 堆在内存物理上可能不连续,但是对于我们使用来说,逻辑上是连续的
    • 虚拟机实现堆是可扩展的,通过参数 -Xmx 和 -Xms 设置
    • 在堆中没有内存可以进行实例分配时,也无法扩展,则会抛出 OutOfMemoryError 异常
  6. 方法区:与 Java堆 一样是线程共享的,用于存储已被虚拟机加载的类型信息、常量、静态变量、即时编译器编译后的代码缓存等数据。注意:经常会将“永久代”和方法区混淆,他们的区别是 方法区是 JVM 的一种规范,而永久代是对这一种规范的实现。查看:方法区和永久代区别。特点如下:

    • 在 jdk7 中已经将字符串常量池从方法区移除,并在Java堆中开辟一块新的区域存放字符串常量池
    • 在 jdk8 中将永久代去除了,使用元空间来实现,元空间的内存区域使用本地内存
    • 如果方法区无法满足新的内存分配需求时,将抛出 OutOfMemoryError 异常
  7. 运行时常量池:运行时常量池是方法区的一部分,存放编译器生成的各种字面量和符号引用。特点如下:

    • 具备动态性,常量池的数据不是都在编译器存入的,还可以在运行时添加,比如 String 的 intern() 方法
    • 常量池无法申请到内存时抛出 OutOfMemoryError 异常
    • 对于各个版本方法区的区别如表格 1-1
  8. 直接内存:直接内存不是虚拟机运行时数据的一部分,其分配不会受到 Java 堆大小的限制。

    • 在 JDK1.4 中新加入了 NIO 类,它可以使用 Native 函数库直接分配堆外内存,在一些场景能显著提高性能
    • 也可能出现 OutOfMemoryError 异常

表格 1-1

jdk1.7以前jdk1.7jdk1.8
字符串常量池在方法区中,实现为永久代字符串常量池在堆中,实现为永久代字符串常量池在堆中,实现为元空间

深入理解Java虚拟机第三版》

©️2020 CSDN 皮肤主题: 我行我“速” 设计师:Amelia_0503 返回首页