Java 虚拟机可以看作一台抽象的计算机,如同真实的计算机,它也有自己的指令集和运行时内存区域。

Java 虚拟机在执行 Java 程序的过程中会把它所管理的内存(运行时内存区域)划分为若干个不同的数据区域。

如下图所示:

一、程序计数器 Program Counter Register

1.定义:程序计数器是当前线程所执行字节码的行号指示器。

2.线程私有内存的原因:Java 中的多线程是线程间轮流切换并需要 CPU 给予时间片的方式实现的。在任何一个确定的时刻,都只有一个线程在执行指令。为了线程间轮流切换后能够快速恢复到正确执行的位置,每一个线程都有自己的程序计数器,各线程间程序计数器互不影响,独立存在。因此,程序计数器是 “线程私有” 的内存区域。

3.详解:在当前线程执行 Java 指令时,程序计数器中存储的是正在执行的字节码的地址;而当前线程执行 native 方法时,程序计数器存储值为空。

字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理、线程回复等基础功能都需要依赖这个计数器来完成。

4.可能导致的错误:程序计数器是 Java 运行时内存区域中唯一一个不会抛出 OutOfMemoryError (OOM)情况的内存区域。

二、Java 虚拟机栈 JVM Stacks

1.定义:Java 虚拟机栈描述的是 Java 方法执行的内存模型。

2.线程私有内存的原因:在当前线程执行方法时,Java 虚拟机栈会创建一个对应该方法的栈帧(Stack Frame)。栈帧中有 局部变量表、操作数栈、动态链接和方法出口等信息。

每一个方法从调用到执行完成时,都对应着栈帧从入栈到出栈的过程。

3.详解:局部变量表存放了各种编译器可知的基本数据类型、对象引用类型和 returnAddress 类型。局部变量表大小在编译期就已确定了,当进入一个方法时,栈帧需要分配给局部变量表的内存空间早已固定,不会再做更改。

(关于 JVM Stacks 的详细情况可能放在 本系列 JVM 执行引擎 一文 中)

4.可能抛出的错误:

  1.当请求的栈深度超越规定的栈深度时,便会抛出 StackOverflowError (sof) 异常

  2.虚拟机栈动态扩展时,如果无法申请到足够的内存,抛出 OOM 异常

三、本地方法栈

1. 定义:本地方法栈描述的是运行时 native 方法的内存模型。

2.解释:本地方法栈与 Java 虚拟机栈几乎相同,只不过本地方法栈对应的是本地方法,Java 虚拟机栈对应的是 Java 方法。

  Hotspot 虚拟机将 java 虚拟机栈与本地方法栈合二为一。

3.可能抛出的异常同 Java 虚拟机栈一样(SOF,OOM)

本地方法的解释:Java 本地方法

四、Java 堆

1. 定义:Java 堆是一块用来存放对象实例的运行时内存空间。

2.Java 堆唯一目的就是用来存放对象实例。几乎所有的对象实例(包括数组)都会在这里分配内存。属于“线程共享"的内存区域。

Java 堆是垃圾回收器管理的主要区域。Java 虚拟机可以处于物理上的不连续内存空间中,只要逻辑上是连续的内存空间即可。

java 堆是垃圾回收的主要区域

3.可能抛出的异常:

  如果堆中没有内存完成实例分配,并且堆再也无法扩展时,那么会抛出 OOM 异常

五、方法区

1.定义:方法区用于存储已被虚拟机加载的类的结构信息、常量、静态变量、即时编译器编译后的静态代码等数据。

方法区是线程共享的内存区域。

2.解释:在 Hotspot 虚拟机上,方法区采用永久代的方式实现,因此方法区又被称为永久代(Permanent Generation),实际上这两者并不等价。因为这样实现的方法区不仅容易遇到内存溢出的问题,而且极少数方法(String.intern) 也会在不同的虚拟机上有不同的表现。

Hotspot 虚拟机现在也有放弃永久代而采用 Native Memory 来实现方法区的规划了(在 JDK1.7 中,将放在永久代的字符串常量池移出)。

对于垃圾回收而言,方法区主要集中在常量池的回收和类类型的卸载这两方面。但是方法区的垃圾回收效果可谓是差强人意,特别是类类型的卸载,不过这部分类型的回收又是必须的。

3. 可能抛出的异常:

  方法区如果无法满足内存分配需求时,将会抛出 OOM 异常。

5.1 方法区重要组成部分: 运行时常量池 Runtime Constant Pool

1.定义:运行时常量池是 class 文件中每一个类或接口的常量池表的运行时表现形式,包括若干种不同的常量,从编译期可知的数值字面量到必须在运行期解析后才能获得的方法和字段引用。

  每一个运行时常量池都在 Java 虚拟机的方法区中分配,在加载类和接口到虚拟机后,就将相应的常量放入运行时常量池。

2.可能抛出的异常:

  当常量池无法再申请到内存时会抛出 OOM 异常

3.例子:

 public class A {
public static void main(String[] args) {
String a = "abc";
String b = "abc";
System.out.println(a==b);
String c = new String("abc");
System.out.println(a==c);
System.out.println(a==c.intern());
}
}

六、直接内存 Direct Memory

在 JDK1.4 中新加入了 NIO(New Input/Output) 类,引入了一种基于通道(Channel) 与缓冲区(Buffer) 的 I/O 方式,它可以使用 Native 函数库直接分配堆外内存,然后通过一个存储在 Java 堆中的 DirectByteBuffer 对象作为这块内存的引用进行操作。这样能在一些场景中显著提高性能,因为避免了在 Java 堆和 Native 堆中来回复制数据。

显然,本机直接内存的分配不会受到 Java 堆大小的限制,但是,既然是内存,坑定还是受到本机总内存(包括 RAM 以及 SWAP 区或者分页文件)大小以及处理器寻址空间的限制。服务器管理员在配置虚拟机参数时,会根据实际内存设置 -Xmx 等参数信息,但经常忽略直接内存,使得各个内存区域总和大于物理内存限制(包括物理的和操作系统级的限制),从而导致动态扩展时出现 OOM 的异常。

 

JVM 运行时数据区:程序计数器、Java 虚拟机栈和本地方法栈,方法区、堆以及直接内存的更多相关文章

  1. JDK1.8-Java虚拟机运行时数据区域和HotSpot虚拟机的内存模型

    目录 介绍 官方文档规定的运行时数据区域 程序计数器 Java虚拟机栈 本地方法栈 虚拟机栈和本地方法栈溢出 Java堆 演示堆内存溢出 方法区 运行时常量池 演示方法区溢出 HotSpot虚拟机的内 ...

  2. Jvm运行时数据区 —— Java虚拟机结构小记

    关于jvm虚拟机的文章网上都讲烂了.尤其是jvm运行时数据区的内容. 抱着眼见为实的想法,自己翻了翻JVM规范,花了点时间稍微梳理了一下. 以下是阅读Java虚拟机规范(Java SE 8版)的第二章 ...

  3. Java内存管理:Java内存区域 JVM运行时数据区

    转自:https://blog.csdn.net/tjiyu/article/details/53915869 下面我们详细了解Java内存区域:先说明JVM规范定义的JVM运行时分配的数据区有哪些, ...

  4. 深入理解Java虚拟机 -- 读书笔记(1):JVM运行时数据区域

    深入理解Java虚拟机 -- 读书笔记:JVM运行时数据区域 本文转载:http://blog.csdn.net/jubincn/article/details/8607790 本系列为<深入理 ...

  5. Java中的字符串常量池和JVM运行时数据区的相关概念

    什么是字符串常量池 JVM为了减少字符串对象的重复创建,其维护了一个特殊的内存,这段内存被成为字符串常量池或者字符串字面量池 工作原理 当代码中出现字面量形式创建字符串对象时,JVM首先会对这个字面量 ...

  6. Jvm运行时数据区

    一:运行时数据区 Java虚拟机在执行Java程序的过程中会把它管理的内存分为若干个不同的数据区域.这些区域有着各自的用途,一级创建和销毁的时间,有的区域随着虚拟机进程的启动而存在,有些区域则依赖用户 ...

  7. JVM运行时数据区内容简述

    JVM运行时数据区分为五个部分:程序计数器.虚拟机栈.本地方法栈.堆.方法区.如下图所示,五部分其中又分为线程共享区域和线程私有区域,下面将分别介绍每一部分. 1. PC程序计数器 程序计数器是一块较 ...

  8. JVM 运行时数据区 (三)

    JVM运行时数据区 运行时数据区由 程序计数器.java虚拟机栈.本地方法栈.堆.方法区 组成: 1.程序计数器 每一个Java线程都有一个程序计数器,用于保存程序执行到当前方法的哪一个指令,它是线程 ...

  9. JVM总结(一):概述--JVM运行时数据区

    大三下,趁着寒假重温一遍JVM,准备在一个系列来总价一下学习JVM的整个过程.争取在接下来的一个星期内更新完这一个系列,然后回家过年. JVM运行时数据区 线程私有的数据区 程序计数器 虚拟机栈 本地 ...

  10. JVM运行时数据区和垃圾回收机制

    最近参考各种资料,尤其是<深入理解Java虚拟机 JVM高级特性和最佳实践>,大牛之作.把最近学习的Java虚拟机组成和垃圾回收机制总结一下. 你不会的都是新知识,学无止境,每天进步一点点 ...

随机推荐

  1. Flask的响应及request属性整理

    类比django框架,Response三贱客: return  HttpResponse:  return ‘xxxxxxxxxx’                 # 返回字符串 return  r ...

  2. 趣谈Linux操作系统学习笔记:第二十七讲

    一.文件系统的功能规划 1.引子 咱们花了这么长的时间,规划了会议室管理系统,这样多个项目执行的时候,隔离性可以得到保证. 但是,会议室里面被回收,会议室里面的资料就丢失了.有一些资料我们希望项目结束 ...

  3. Computer-Hunters——团队展示

    Computer-Hunters--团队展示 这个作业属于哪个课程 https://edu.cnblogs.com/campus/fzu/2019FZUSEZ 这个作业要求在哪里 https://ed ...

  4. 一些树上dp的复杂度证明

    以下均为内网 树上染色 https://www.lydsy.com/JudgeOnline/problem.php?id=4033 可怜与超市 http://hzoj.com/contest/62/p ...

  5. 应用JWT进行用户认证及Token的刷新

    本文将通过实际的例子来演示如何在ASP.NET Core中应用JWT进行用户认证以及Token的刷新方案(ASP.NET Core 系列目录) 一.什么是JWT? JWT(json web token ...

  6. ShowDoc 软件开发团队接口文档管理利器

    ShowDoc是一个非常适合IT团队的在线API文档.技术文档工具.你可以使用Showdoc来编写在线API文档.技术文档.数据字典.在线手册. 这里介绍 Showdoc 这款开源(免费)文档管理系统 ...

  7. 关于深度学习框架 TensorFlow、Theano 和 Keras

    [TensorFlow] ——( https://morvanzhou.github.io/tutorials/machine-learning/tensorflow/) 1.TensorFlow是啥 ...

  8. Linux驱动架构之pinctrl子系统分析(一)

    1.前言在嵌入式系统中,许多SoC的内部都包含了pin控制器,通过芯片内部的pin控制器,我们可以配置一个或者一组引脚的状态和功能特性,Linux内核为了统一各SoC厂商的引脚管理,提供了pinctr ...

  9. JavaSE 笔试题: 自增变量

    JavaSE 笔试题 自增变量 public class Test { public static void main(String[] args) { int i = 1; i = i++; int ...

  10. 第二节:EF Core的常规“增删改”及状态的变化

    一. 整体说明 1. 本节用到的表 2. 状态说明补充 ①.Detached: 游离的状态,与数据库没有什么交涉,比如新new一个实体,状态就是Detached. ②.Added: 增加的状态. ③. ...