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.例子:

  1. public class A {
  2. public static void main(String[] args) {
  3. String a = "abc";
  4. String b = "abc";
  5. System.out.println(a==b);
  6. String c = new String("abc");
  7. System.out.println(a==c);
  8. System.out.println(a==c.intern());
  9. }
  10. }

六、直接内存 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. java web开发入门汇总

    servlet 用java语言开发动态资源网站的技术,在doGet方法中拼接显示html,在doPost方法中提交数据.类似于.net的ashx技术. servlet生成的class文件存放在tomc ...

  2. 苹果 appstore 上架 ipv6 服务 配置

    前言 好久之前的事了,苹果审核突然要求ipv6,一片哀嚎. 研究了好久找到了基于阿里云经典网络Windows Server的配置方法. https://bbs.aliyun.com/read/2849 ...

  3. Win10,Anaconda,tensorflow-gpu安装教程

    ,参考于:https://www.cnblogs.com/guoyaohua/p/9265268.html 目录 前言 第一步:安装Anaconda 1.下载和安装 2.配置Anaconda环境变量 ...

  4. libevent笔记4:Filter_bufferevent过滤器

    Filter_bufferevent是一种基于bufferevent的过滤器,其本身也是一个bufferevent.能够对底层bufferevent输入缓存区中的数据进行操作(加/解密等)后再读取,同 ...

  5. 【2019年06月28日】A股最便宜的股票

    查看更多A股最便宜的股票:androidinvest.com/CNValueTop/ 经典价值三因子选股: 市盈率PE.市净率PB 和 股息分红率,按照 1:1:1的权重,选择前10大最便宜的股票. ...

  6. shell三剑客之grep

    背景 对于很多的测试人员来说,grep命令都很熟悉,用的最多的比如去查找指定的进程:ps -ef | grep *** ,其中***为进程名或进程号,这里我们只用到的grep的最基础功能-从标准输出中 ...

  7. Prometheus安装部署说明

    本文主要介绍了如何二进制安装Prometheus.使用 Node Exporter 采集主机信息并使用Grafana来进行图形化的展示. 1. 安装Prometheus Server Promethe ...

  8. [转帖]ps 命令详解

    ps 命令详解 https://www.jianshu.com/p/cba22cce2f97 ps 概述 Linux中的ps命令是Process Status的缩写.ps命令用来列出系统中当前运行的那 ...

  9. C语言函数调用

    1.backtrace一些内存检测工具如Valgrind,调试工具如GDB,可以查看程序运行时函数调用的堆栈信息,有时候在分析程序时要获得堆栈信息,借助于backtrace是很有帮助的,其原型如下: ...

  10. CentOS7安装Node_exporter(二进制)

    一.概述 Node_exporter是可以在* Nix和Linux系统上运行的计算机度量标准的导出器.Node_exporter 主要用于暴露 metrics 给 Prometheus,其中 metr ...