Java 虚拟机定义了在程序执行期间使用的各种运行时数据区域。

其中一些数据区域所有线程共享,在 Java 虚拟机(JVM)启动时创建,仅在 Java 虚拟机退出时销毁。

还有一些数据区域是每个线程的。线程数据区域是在线程启动时创建,线程结束时销毁。

一、运行时数据区划分(JDK8)

1、The pc Register(PC 寄存器、程序计数器)

2、Java Virtual Machine Stacks(Java 虚拟机栈、Java 栈)

3、Native Method Stacks(本地方法栈,C栈)

4、Heap(堆)

5、Method Area(方法区,JDK8 中的实现叫元数据区(本地内存中),JDK7 中的实现叫永久代(JVM中))

6、Run-Time Constant Pool(运行时常量池,方法区的一部分)

二、区划分详情

2.1.The PC Register(PC 寄存器)

每个 JVM 线程都有自己的 pc 寄存器(内存为线程私有,随着线程的创建而创建,线程的结束而销毁)。

在任何时候,每个 JVM 线程都在执行单个方法的代码,即该线程的当前方法(字节码解释器通过改变程序计数器来选取下一条需要执行指令,从而实现代码的流程控制,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成)。

如果该方法不是 native,则 pc 寄存器包含当前正在执行的 JVM 指令的地址(线程切换就知道上次线程执行到哪了)。

如果该方法是 native,则 pc 寄存器为 Undefined(不会 OutOfMemoryError)。

2.2.Java Virtual Machine Stacks(Java 虚拟机栈)

描述 Java 方法执行的内存模型。

每个 JVM 线程都有一个私有 JVM 栈,与线程同时创建(内存为线程私有,随着线程的创建而创建,线程的结束而销毁)。

JVM 栈存储 frames (栈帧)。方法调用和返回对应压栈和出栈(栈顶的栈帧是当前正在执行的活动栈,也就是当前正在执行的方法,PC 寄存器也会指向这个地址,只有这个活动的栈帧的本地变量可以被操作数栈使用)。

由于除了压栈和出栈之外,永远不会直接操作 JVM 栈,JVM 栈的内存不需要是连续的。

JVM 规范允许 JVM 栈具有固定大小,也可以根据计算的需要动态扩展和收缩(通过 -Xss 控制)。

以下异常与 JVM 栈有关:

如果不可以动态扩展 Java 虚拟机栈,当线程中的方法调深度用超过 Java 虚拟机栈最大深度时,会抛出 StackOverflowError 异常(出现 StackOverFlowError 时,内存空间可能还有很多)。

如果可以动态扩展 Java 虚拟机栈,当线程尝试进行扩展但可使内存不足以实现扩展,或者可使内存不足以为新线程创建初始 Java 虚拟机堆栈时,会抛出 OutOfMemoryError 异常。

2.3.Native Method Stacks(本地方法栈)

描述本地方法运行过程的内存模型。

JVM 可以使用常规栈来支持 native 方法(用 Java 编程语言以外的语言编写的方法,执行也会创建栈帧)。

无法加载 native 方法,并且本身不依赖于传统堆栈的 JVM, 不需要提供本地方法栈。如果提供,则通常在每个线程创建时分配本地方法栈。

本地方法栈具有固定大小,也可以根据计算的需要动态扩展和收缩。

以下异常与本地方法栈有关:

如果不可以动态扩展本地方法栈,当线程中的计算需要比允许的本地方法栈更大,则会抛出 StackOverflowError 异常。

如果可以动态扩展本地方法栈,当尝试进行本地方法栈扩展,但可使内存不足,或没有足够的内存可用于为当前前程创建初始本地方法栈,则会抛出 OutOfMemoryError 异常。

2.4.Heap(堆)

堆是运行时数据区,从中分配所有类实例和数组的内存(JVM 中内存最大的一块,被所有线程共享,需要注意同步问题)。

堆是在 JVM 启动时创建的。

堆中对象的存储由垃圾收集器(GC,自动存储管理系统)回收,对象永远不会被显式释放。

JVM 没有特定类型的 GC,可以根据实现者的系统要求选择存储管理技术。

堆可以具有固定大小,也可以根据计算的需要进行扩展(通过 -Xmx 和 -Xms 控制)。堆的内存不需要是连续的。

以下异常情况与堆有关:

如果计算需要的堆量超过自动存储管理系统可用的堆,则会抛出 OutOfMemoryError 异常。

2.5.Method Area(方法区)

方法区在所有 JVM 线程之间共享。方法区是在 JVM 启动时创建的。方法区在逻辑上是堆的一部分,但可选择不实现垃圾回收。

方法区存储类结构,如运行时常量(Run-Time Constant Pool),字段和方法数据,以及方法和构造函数的代码,包括类和实例初始化以及接口初始化中使用的特殊方法

JVM 规范未规定方法区的位置或用于管理编译代码的策略。

方法区可以是固定大小的,也可以根据计算的需要进行扩展。方法区的内存不需要是连续的。

以下异常与方法区有关:

如果方法区域中的内存无法满足分配请求,会抛出 OutOfMemoryError 异常。

2.6.Run-Time Constant Pool(运行时常量池)

运行时常量池是方法区的一部分。

Class 文件中的常量池(constant_pool Table),用于存放编译期生成的各种字面量和符号引用,这部分在类加载后进入方法区的运行时常量池中。

在运行期间,也可以向常量池中添加新的常量。如 String 类的 intern() 方法。

每个运行时常量池都是从 JVM 的方法区中分配的。

以下异常与类或接口的运行时常量池的构造有关:

在创建类或接口时,如果运行时常量池的构造需要的内存比 JVM 方法区中可用的内存多,会抛出 OutOfMemoryError 异常

三、直接内存(堆外内存)

不是 JVM 运行时数据区的一部分,但这部分内存也会被频繁的使用,也可能导致 OutOfMemoryError 异常。

JDK 1.4 中新加入了 NIO 类,通过调用本地方法直接分配 Java 虚拟机之外的内存,然后通过一个存储在堆中的 DirectByteBuffer 对象直接操作该内存。

避免了 Java 堆和 Native 堆来回交换数据的时间,更高效。

四、大概划分图(JDK8-HotSpot)


https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-2.html#jvms-2.5

http://www.hollischuang.com/archives/2509

https://github.com/doocs/jvm/blob/master/docs/01-jvm-memory-structure.md

https://my.oschina.net/u/3471412/blog/3001024

Java-JVM 运行时内存结构(Run-Time Data Areas)的更多相关文章

  1. JVM 运行时内存结构

      1.JVM内存模型       JVM运行时内存=共享内存区+线程内存区 1).共享内存区       共享内存区=持久带+堆       持久带=方法区+其他       堆=Old Space ...

  2. JVM运行时内存结构

    原文转载自:http://my.oschina.net/sunchp/blog/369707 1.JVM内存模型 JVM运行时内存=共享内存区+线程内存区 1).共享内存区 共享内存区=持久带+堆 持 ...

  3. [转]JVM运行时内存结构

    [转]http://www.cnblogs.com/dolphin0520/p/3783345.html 目录[-] 1.为什么会有年轻代 2.年轻代中的GC 3.一个对象的这一辈子 4.有关年轻代的 ...

  4. JVM运行时内存结构学习

    学习JVM运行模型比较重要,先看一幅图片: 运行时数据区(内存结构) :  1.方法区(Method Area)类的所有字段和方法字节码,以及一些特殊方法如构造函数,接口代码也在这里定义.简单来说,所 ...

  5. Java程序运行时内存划分

    1.Java程序跨平台运行的原因 主要原因是:各种平台的JVM和字节码文件 Java源程序--具体平台的机器代码文件---被编译器翻译成平台无关的Class文件,又用特定JVM运行字节码文件,JVM在 ...

  6. 详细了解JVM运行时内存

    详细了解JVM运行时内存 1.程序计数器 概念 程序计数器也叫作PC寄存器,是一块很小的内存区域,可以看做是当前线程执行的字节码的行号指示器.字节码的解释工作就是通过改变程序计数器里面的值来获得下一条 ...

  7. JVM运行时内存组成分为一些线程私

    JVM运行时内存组成分为一些线程私有的,其他的是线程共享的. 线程私有 程序计数器:当前线程所执行的字节码的行号指示器. Java虚拟机栈:java方法执行的内存模型,每个方法被执行时都会创建一个栈帧 ...

  8. java程序运行时内存分配详解

    java程序运行时内存分配详解 这篇文章主要介绍了java程序运行时内存分配详解 ,需要的朋友可以参考下   一. 基本概念 每运行一个java程序会产生一个java进程,每个java进程可能包含一个 ...

  9. Jvm运行时内存解析

    一.jvm的概念 在了解jvm的概念之前,我们先来了解java平台的逻辑结构,图片来自<深入java虚拟机> 从图中我们可以看到jdk包含了jre,java语言和java开发工具和Api, ...

随机推荐

  1. 6 java 笔记

    1 java的类通过构造器来创建该类的对象 2 java提供extends关键字来实现子类继承父类 3 初始化块总是在构造器调用之前被执行 4 可以吧java中的类当成一种自定义的类型 5 类定义的变 ...

  2. Spring MVC之@RequestParam @RequestBody @RequestHeader 等详

    Spring MVC之@RequestParam @RequestBody @RequestHeader 等详     引言: 接上一篇文章,对@RequestMapping进行地址映射讲解之后,该篇 ...

  3. vue下载后台传过来的乱码流的解决办法

    后台返回的乱码流 解决办法: 请求方式用的是axios,主要加关键的 {responseType: 'blob'} axios封装 export function postDownload(url, ...

  4. 第十章、os模块

    目录 第十章.os模块 一.os模块 第十章.os模块 一.os模块 方法 详解 os.getcwd() 获取当前工作目录,即当前python脚本工作的目录路径 os.chdir("dirn ...

  5. Delphi DLL文件的静态调用

  6. c++第三次作业:类的友元

    C++第三次作业:类的友元 1.友元的关系提供了不同类或对象的成员函数之间.类的成员函数与一般函数之间进行数据共享的机制.通俗的说友元关系就是一个类主动声明其他函数是他的朋友,可以使其获得特殊访问权利 ...

  7. ACwing 196. 质数距离

    #include <bits/stdc++.h> using namespace std; , M = ; int v[M]; long long prime[N],prim[N]; ; ...

  8. The Tower HDU - 6559 (解析几何)

    The Tower HDU - 6559 The Tower shows a tall tower perched on the top of a rocky mountain. Lightning ...

  9. Can you answer these queries I SPOJ - GSS1 (线段树维护区间连续最大值/最大连续子段和)

    You are given a sequence A[1], A[2], ..., A[N] . ( |A[i]| ≤ 15007 , 1 ≤ N ≤ 50000 ). A query is defi ...

  10. java8学习之BiFunction函数式接口实例演示&Predicate函数式接口详解

    BiFunction函数式接口: 在上次中已经对BiFunction接口进行了初步的认识,这里对它进一步学习,这里打算新建一个Person实体,然后新建若干个Person的实例存放在集合中,最后再根据 ...