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

1. PC程序计数器

程序计数器是一块较小的空间,他的作用可看作是当前线程所执行的字节码的行号指示器。一个线程的挂起和恢复依赖于本区域,比如当一个线程因为发生某种情况需要挂起时,为了下一次恢复程序能从本次暂停区域继续执行,此时需要记录本线程挂起时运行到的位置。每条线程都需要一个独立的程序计数器,每条线程之间的计数器互不影响,独立存储,我们称这部分内存区域为线程私有的内存。由于本区域只需要存储线程执行到的地址,所以本区域是唯一一个不会发生OutOfMemoryError。

2. 虚拟机栈

与程序计数器一样,本区域也是线程私有的,他的生命周期与线程的生命周期相同。JVM Stack 描述的是Java方法执行的内存模型,每个方法被执行时都会创建一个栈帧,用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法被调用直至执行完成的过程,就对应着一个栈帧在虚拟机中从入栈到出栈的过程。

当线程申请的栈深度大于JVM Stack所允许的最大深度时,JVM会抛出OverStackFlowError错误。JVM Stack的大小也是动态变化的,当内存不够时,系统会自动扩展,无法扩展时JVM会抛出OutOfMemoryError错误。

3. 本地方法栈

本区域也是线程私有的,其作用与上述虚拟机栈作用类似,不过不同的是其所服务的是本地方法。本地方法栈也会抛出OverStackFlowError和OutOfMemoryError错误。

4.Java 堆

Java堆是虚拟机所管理的内存中最大的一部分,正如上图所示,Java堆是所有线程共享的区域,本区域唯一的目的就是存储Java的实例对象,几乎所有的对象实例都在这里分配空间。堆也是JVM进行垃圾回收的主要区域,因此很多时候也被称为GC堆(Garbage Heap)。如果在堆中没有内存再完成实例分配,并且堆无法继续扩展时,本区域也会抛出OutOfMemoryError。另外原先处与方法区的运行时常量池在JDK 1.7之后也被移到了Java 堆中。

5. 方法区

与Java一样,本区域也是所有线程的共享区域,它用于存储已经被虚拟机加载的类信息、常量、静态变量、编译器编译后的代码等数据。根据JVM规范,当方法区无法满足内存分配时也会抛出OutOfMemoryError异常。

6. 运行时常量池

运行时常量池是方法区的一部分(jdk1.7之前)。Class文件中除了有关类的版本、字段、方法、接口等描述信息外,还有一项信息是常量池,用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后进入方法区的运行时常量池中存放。

运行时常量池相对于Class文件常量池的另一个重要特征是具备动态性,Java语言并非不要求常量一定只有编译期才能产生,也就是并非预置入Class文件中常量池的内容才能进入方法区运行时常量池,运行期间也可以将新的常量池放入池中。

在实验验证周志明老师的深入理解JVM中的相关代码时,关于Java内存区域与内存溢出异常,运行下面这段代码(为了保证很快出现溢出错误,我们使用设置JVM运行参数-Xmx5m -XX:MaxPermSize=1M):

	public static void main(String[] args) throws Throwable {
List<String> list = new ArrayList<String>();
int i=0;
while(true){
list.add(String.valueOf(i++).intern());
System.out.println(i);
}
}

在我的环境(jdk 1.8)下发生的错误为:

Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceeded
at java.lang.Integer.toString(Unknown Source)
at java.lang.String.valueOf(Unknown Source)
at Test.main(Test.java:13)

并不是书中所描述的PermGen space溢出。所以又回头看出现的错误是GC overhead limit exceeded所以猜测运行时常量池是改变了位置?发现网上有很多这种验证运行时常量池被挪到了Java 堆中,这个也很容易验证,首先,源代码不变,增加运行时JVM的参数: -Xmx20m -Xms20m -XX:-UseGCOverheadLimit,这里的-XX:-UseGCOverheadLimit是关闭GC占用时间过长时会报的异常,然后限制堆的大小,运行程序,果然,一会后报异常:

Exception in thread “main” java.lang.OutOfMemoryError: Java heap space

从上面的异常可以知道我们测试增加的常量都放到了堆中。另外找到了关于官网对这点的说明:https://www.oracle.com/technetwork/java/javase/jdk7-relnotes-418459.html


参考资料:

深入理解Java虚拟机,周志明

https://www.jianshu.com/p/460aeab77b7f

https://www.jianshu.com/p/6173a467165e


JVM运行时数据区内容简述的更多相关文章

  1. Jvm运行时数据区

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

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

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

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

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

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

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

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

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

  6. JVM运行时数据区及对象在内存中初始化的过程

    JVM运行时数据区 Java虚拟机所管理的内存区域,也称为运行时数据区,分为以下几个运行时数据区,如图所示 程序计数器:当前程序所执行字节码的行号指示器 程序计数器(Program Counter R ...

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

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

  8. JVM运行时数据区与JVM堆内存模型小结

    前提 JVM运行时数据区和JVM内存模型是两回事,JVM内存模型指的是JVM堆内存模型. 那JVM运行时数据区又是什么? 它包括:程序计数器.虚拟机栈.本地方法栈.方法区.堆. 来看看它们都是干嘛的 ...

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

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

随机推荐

  1. 新特技软件(Analyzer)添加新用户

    新特技软件添加新用户的步骤比较多,记录下来,方便以后使用 安装完软件,处理好自己的AS以后,准备添加用户 步骤一: 我们要在安装Analyzer的服务器上添加新的Windows用户 步骤二:在Anal ...

  2. 【病毒分析】对一个vbs脚本病毒的分析

    [病毒分析]对一个vbs脚本病毒的分析 本文来源:i春秋社区-分享你的技术,为安全加点温度 一.前言 病毒课老师丢给我们一份加密过的vbs脚本病毒的代码去尝试分析,这里把分析过程发出来,供大家参考,如 ...

  3. JS创建对象,数组,函数的三种方式

    害怕自己忘记,简单总结一下 创建对象的3种方法 ①:创建一个空对象   var obj = {}; ②:对象字面量 var obj = { name: "Tom", age: 27 ...

  4. Kali学习笔记19:NESSUS安装及使用

    Nessus 百度百科:Nessus 是目前全世界最多人使用的系统漏洞扫描与分析软件.总共有超过75,000个机构使用Nessus 作为扫描该机构电脑系统的软件. 就我而言:漏洞扫描方面最强大的工具之 ...

  5. Centos 基本命令不能用恢复方法

    遇到命令都不能用,直接执行下面的语句就可以: export PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/roo ...

  6. ffmpeg常用转换命令

    音频转换: 1.转换amr到mp3: ffmpeg -i shenhuxi.amr amr2mp3.mp3 2.转换amr到wav: ffmpeg -acodec libamr_nb -i shenh ...

  7. os模块及其API&属性

    模块: os os.path 所包含API列表: os.uname: 获取详细的系统信息 os.rename: 文件重命名 os.remove: 删掉文件 os.mkdir: 创建一个目录 os.rm ...

  8. 删除github上面的项目

    1.进入github 2.点击Repositories,看到你所有的repository 3.点击进入你想要删除的repository,点击settings 4.在options选项中,下拉到底看到“ ...

  9. sql server 索引阐述系列三 表的堆组织

    一.   概述 这一节来详细介绍堆组织,通过讲解堆的结构,堆与非聚集索引的关系,堆的应用场景,堆与聚集索引的存储空间占用,堆的页拆分现象,最后堆的使用建议 ,这几个维度来描述堆组织.在sqlserve ...

  10. Apache-Flink深度解析-State

    摘要: 实际问题 在流计算场景中,数据会源源不断的流入Apache Flink系统,每条数据进入Apache Flink系统都会触发计算.如果我们想进行一个Count聚合计算,那么每次触发计算是将历史 ...