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. 4.移动端自动化测试-API讲解

    一.前置代码 1.导入driver对象    from appium import webdriver 2.声明手机驱动对象  只有声明驱动对象我们才可以让手机完成脚本的操作    driver = ...

  2. idea中安装git后,代码颜色代表的含义

    idea中安装git以后,代码文件出现了不同的颜色 它们分别表示的含义: 绿色,已经加入控制暂未提交 红色,未加入版本控制 蓝色,加入,已提交,有改动 白色,加入,已提交,无改动 灰色:版本控制已忽略 ...

  3. linux命令详解——sar

    Linux统计/监控工具SAR详细介绍:要判断一个系统瓶颈问题,有时需要几个 sar 命令选项结合起来使用,例如:怀疑CPU存在瓶颈,可用 sar -u 和 sar -q deng 等来查看 怀疑内存 ...

  4. python中的负数取模问题(一个大坑)

    先来看一段代码 这是什么情况?为什么会出现这种结果.我们再来看看其它语言的执行结果 我们用golang.js.c分别算了一下,结果得到的结果都是一致的,但是python为啥不一样呢? 其实之所以这么做 ...

  5. Linux下周期性查看GPU状态

    Linux下周期性查看GPU状态 NVIDIA自带了nvidia-smi命令来查看GPU的使用情况 了解一下watch命令 $ whatis watch watch (1) - execute a p ...

  6. Scala(二)——基础语法(与Java的区分)和函数式编程

    Scala快速入门(二) 一.键盘输入 关于基本类型的运算,以及复制运算,条件运算,运算符等知识,均和Java语言一样,这里不过多叙述. val name = StdIn.readLine() Std ...

  7. 在RecyclerView中集成QQ汽泡二

    上次已经将GooView集成到RecyclerView当中了[http://www.cnblogs.com/webor2006/p/7787511.html],但是目前还有很多问题,下面先来运行看一下 ...

  8. Springboot整合Ehcache 解决Mybatis二级缓存数据脏读 -详细

    前面有写了一篇关于这个,但是这几天又改进了一点,就单独一篇在详细说明一下 配置 application.properties ,启用Ehcache # Ehcache缓存 spring.cache.t ...

  9. React组件:Dragact 0.1.4发布

    Dragact 是一款React组件,他能够使你简单.快速的构建出一款强大的 拖拽式网格(grid)布局. 仓库地址:Dragact 经过几天的迭代时间Dragact已经能够支持自由缩放功能了(res ...

  10. 部署dashboard

    1.获取k8s版本: 2.访问dashboard的github:https://github.com/kubernetes/dashboard/releases,然后找到对应的版本 3.然后将yaml ...