关于jvm:jvm运行时数据区域有哪些

31次阅读

共计 3916 个字符,预计需要花费 10 分钟才能阅读完成。

JVM 运行时数据分为几大部分:

  1. 程序计数器
  2. Java 虚拟机栈
  3. 本地办法栈
  4. Java 堆
  5. 办法区
  6. 运行时常量池
  7. 间接内存

1. 程序计数器

程序计数器(Program Counter Register)是 一块较小的内存空间 ,它能够看作是 以后线程所执行的字节码的行号指示器 。在虚拟机的概念模型里,字节码解释器工作时就是通过 扭转这个计数器的值 来选取下一条须要执行的字节码指令,分支、循环、跳转、异样解决、线程复原等根底性能都须要依赖这个计数器来实现。

因为 Java 虚拟机的多线程是通过线程轮流切换并调配 CPU 工夫片的形式来实现的,在任何一个确定的时刻,一个处理器都只会执行一条线程中的指令。因而,为了线程切换后能复原到正确的执行地位,每条线程都须要有一个独立的程序计数器,各条线程之间计数器互不影响,独立存储,咱们称这类内存区域为“线程公有的内存”。

如果线程正在执行的是一个 Java 办法,这个计数器记录的是正在执行的虚拟机字节码指令的地址;如果正在执行的是 Native 办法,这个计数器值则为空(Undefined),此内存区域是惟一一个在 Java 虚拟机标准中没有规定任何 OutOfMemoryError 状况的区域。

2. Java 虚拟机栈

与程序计数器一样,Java 虚拟机栈也是线程公有的,它的生命周期和线程雷同。虚拟机栈形容的是 Java 办法执行的内存模型:每个办法在执行的同时都会创立一个栈桢用于存储 局部变量表、操作数栈、动静链接、办法进口 等信息。每一个办法从调用直至执行实现的过程,就对应一个栈帧在虚拟机中入栈到出栈的过程。

人们常常把简略的虚拟机分为堆和栈,而这个栈就是当初讲的虚拟机栈,或者说是虚拟机栈中局部变量表局部。

局部变量表寄存了编译器可知的各种根本类型(boolean、byte、char、short;int、float、long、double),对象援用(reference 类型,可能是指向对象起始地址的援用指针,也可能是指向一个代表对象的句柄或其余与此对象相干的地位)和 returnAddress 类型(指向了一条字节码指令的地址)。

其中 64 位的 long 和 double 类型的数据会占用 2 个局部变量空间,其余的数据类型只占用一个。局部变量表所需的内存空间在编译期间实现调配,当进入一个办法时,这个办法须要在栈中调配多大的局部变量是齐全确定的。在办法运行期间不会扭转局部变量表的大小。

在虚拟机标准中,对这个区域规定了两种异常情况:如果线程申请的栈深度大于虚拟机所容许的深度,将抛出 StackOverflow 异样;如果虚拟机能够动静扩大(以后大部分的 Java 虚拟机都能够动静扩大,只不过 Java 虚拟机标准中也容许固定长度的虚拟机栈),如果扩大时无奈声请到足够的内存,就会抛出 OutOfMemoryError 异样。

3. 本地办法栈(HotSpot 已被交融进虚拟机栈)

本地办法栈(Native Method Stack)和虚拟机栈所产品的作用是十分类似的,他们之间的区别不过是虚拟机栈为虚拟机执行 Java 办法(也就是字节码)服务,而本地办法栈则为虚拟机应用到的 Native 办法服务。而虚拟机标准中对本地办法栈中办法应用的语言、应用形式与数据结构并没有强制规定,因而具体的虚拟机能够自在实现它。甚至有的虚拟机(HotSpot)间接就把本地办法栈和虚拟机栈合二为一。与虚拟机栈一样,本地办法栈区域也会抛出 StackOverflow 异样和 OutOfMemoryError 异样。

4. Java 堆

对于大多数利用来说,Java 堆(Java Heap)是 Java 虚拟机所治理的内存中最大的一块。Java 堆是被所有线程共享的一块内存区域,在虚拟机启动时创立。此内存区域的惟一目标就是寄存对象实例,简直所有的对象实例都再这里分配内存。这一点 Java 虚拟机标准中的形容是:所有的对象实例以及数组都要在堆上调配,然而随着 JIT 编译器的倒退和逃逸剖析技术逐步成熟,栈上调配、标量替换优化技术将会导致一些奥妙的变动产生,所有的对象都调配在堆上也慢慢变得不是那么“相对”了。

Java 堆是垃圾收集器治理的次要区域,因而很多时候也被称为“GC 堆(Garbage Collected Heap)”,从内存回收的角度来看,因为当初收集器根本都采纳分代收集算法,所以 Java 堆中还能够细分成:新生代和老年代;再粗疏一点的有 Eden 空间、From Survivor 空间、To Survivor 空间等。从内存调配的角度来看,线程共享的 Java 堆中可能划分出多个线程公有的调配缓冲区(Thread Lcoal Allocation Buffer,TLAB)。

不过无论如何划分,都与寄存内容无关,无论哪个区域,存储的依然是对象实例,进一步划分的目标是为了更好的回收内存,或者更快的分配内存。

依据虚拟机的规定,Java 堆能够处于物理上不间断的内存空间中,只有逻辑上是间断的即可,就像咱们的磁盘空间一样。在实现时,既能够实现成固定大小的,也能够是可扩大的,不过以后支流的虚拟机都是依照可扩大来实现的(通过 -Xmx 和 Xms 管制)。如果在堆中没有内存实现实例调配,并且堆也无奈扩大时,将会抛出 OutOfMemoryError 异样。

5. 办法区

办法区(Method Area)与 Java 堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、动态变量、即时编译器编译后的代码等数据。尽管 Java 虚拟机标准把办法区形容堆的一个逻辑局部,然而它却有一个别名叫做(Non-Heap 非堆),目标应该是与 Java 堆辨别开来。

对于习惯在 HotSpot 虚拟机上开发,部署程序的开发者来说,很多人都更违心把办法区称为“永恒代(Permanent Generation)”,实质上两者并不等价,仅仅是因为 HotSpot 虚拟机的设计团队抉择把 GC 分代设计扩大至办法区,或者说应用永恒代来实现办法区而已,这样 HotSpot 的垃圾收集器能够像治理 Java 堆一样治理这部分内存,可能省去专门为办法区编写内存治理代码的工作。

对于其余虚拟机并不存在永恒代这个概念。原则上,如何实现 Java 虚拟机属于实现细节,不受虚拟机标准束缚,但应用永恒代来实现办法区,当初看来并不是好主见,因为这样更容易遇到内存溢出(永恒代有 -XX:MaxPermSize 的下限)。

因而,对于 HotSpot 虚拟机,曾经放弃了永恒代并逐渐改为 Native Memory 来实现办法区的布局了,在目前的版本中,曾经把本来放在永恒代的字符串常量池移出。

Java 虚拟机标准对办法区的限度十分宽松,除了和 Java 堆一样不须要间断的内存和能够抉择固定大小或者可扩大外,还能够抉择不实现垃圾回收。相对而言,垃圾收集行为在这个区域是比拟少见的,但并非数据进入了办法区就如同永恒代的名字一样“永恒”存在了。这区域的内存回收指标次要是针对常量池的回收和对类型的卸载,一般来说,这个区域的回收“问题”比拟难以令人满意,尤其是类型的卸载,条件相当刻薄,然而这部分的区域的回收的确是由必要的。Sun 有几个 Bug 就是因为 HotSpot 虚拟机对此区域未齐全回收导致内存透露。

当办法区无奈满足内存调配需要时,会抛出 OutOfMemoryError 异样。

6. 运行时常量池

运行时常量池是办法区的一部分,Class 文件中除了有类的版本、字段、办法、接口等形容信息外,还有一项是常量池(Constant Pool Table),用于寄存编译期生成的各种字面量和符号援用,这部分内容在类加载后进入办法区的运行时常量池中寄存。

JVM 对 Class 文件每一个局部都有严格规定(包含常量池),每一个字节用于存储哪种数据都必须符合规范上的要求才会被虚拟机认可、装载和执行,但对于运行时常量池,Java 虚拟机标准没有做任何细节的要求,不同的厂商实现的虚拟机能够依照本人的须要来实现这个内存区域。不过,一般来说,除了保留 Class 文件中形容的符号援用之外,还会把翻译进去的间接援用也存储在运行时常量池中。

运行时常量池绝对于 Class 文件常量池的另外一个重要特色是具备动态性,Java 语言并不要求常量肯定只有编译期能力产生,也就是并非预置入 Class 文件中常量池的内容能力进入办法区运行时常量池,运行期间也可能将新的常量放入池中,这种个性被开发人员利用比拟多的便是 String 类的 intern() 办法。

既然运行时常量池是办法区的一部分,天然受到办法区内存的限度,当常量池无奈再申请到内存时会抛出 OutOfMemoryError 异样。

7. 间接内存

间接内存(Direct Memory) 并不是 JVM 运行时数据区的一部分,也不是 JVM 标准中定义的内存区域,然而这部分内存也被频繁的应用,而且也可能导致 OutOfMemoryError 异样呈现。

在 JDK 1.4 中新退出了 NIO 类,援用了一种基于通道(Channel)与缓冲区(Buffer)的 I/O 形式,它能够应用 native 函数库间接调配堆外内存,而后通过一个存储在 Java 堆中的 DirectByteBuffer 对象作为这块内存的援用进行操作。这样能在一些场合中显著进步性能,因为防止了在 Java 堆和 Native 堆中来回复制数据。

显然,本机间接内存的调配不会受到 Java 堆大小的限度,然而,既然是内存,必定还是会受到本机总内存(包含 RAM 以及 SWAP 区或者分页文件)大小以及处理器寻址空间的限度。服务器管理员在配置虚拟机总参数时,会依据理论内存设置 -Xmx 等参数信息,但常常疏忽间接内存,使得各个内存区域总和大于物理内存限度(包含物理的和操作系统级别的限度),从而导致动静扩大时呈现 OutOfMemoryError 异样。

正文完
 0