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. windows 下Nginx 入门

    验证配置是否正确: nginx -t 查看Nginx的版本号:nginx -V 启动Nginx:start nginx 快速停止或关闭Nginx:nginx -s stop 正常停止或关闭Nginx: ...

  2. Linux下Mysql 不能访问新数据文件夹问题

    新挂载的盘,打算将数据文件夹配置到 /data/mysql,却无法启动mysqld. 除了将目录授权给mysql用户和组以外 chown -R mysql:mysql /data/mysql 太需要将 ...

  3. 复制SD启动卡 生成新启动卡

    在已经有1张SD卡启动卡的情况下,如何复制出一张新卡: 1. 使用软件DiskGenius4.8.0->硬盘->备份分区表 备份 源sd卡分区信息 2. 使用软件DiskGenius4.8 ...

  4. 第七章 路由 75 路由传参-使用query方式传递参数

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8&quo ...

  5. .net core 读取appsettings 的配置

    { "Logging": { "IncludeScopes": false, "LogLevel": { "Default&quo ...

  6. oracle plsql登陆用户名密码都正确,拒绝登陆

    先通过sqlplus  或者 sql developer 或者其他用户登陆 然后更改 登陆不上的用户的密码  然后再用plsql登陆就可以了  然后还可以再把用户密码再改回来 也可以登陆了

  7. java 如何实现文件变动的监听

    获取修改时间 long lastTime = file.lastModified(); 原文链接:https://blog.csdn.net/liuyueyi25/article/details/79 ...

  8. Linux下DB2指令总结

    1.显示当前实例 >> get instance The current database manager instance is: db2axing 2.列出当前实例中激活的数据库 &g ...

  9. 51nod 1850 抽卡大赛 (十二省联考模测) DP

    O(n4)O(n^4)O(n4)的DP很好想,但是过不了.来看看O(n3)O(n^3)O(n3)的把. Freopen的博客 CODE #include <cstdio> #include ...

  10. SpringBoot对接收及返回Instant类型的处理(转)

    一:处理post请求json中的Instant类型1.springboot中日期格式化配置: spring: jackson: date-format: yyyy-MM-dd HH:mm:ss tim ...