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. Openvswitch手册(5): VLAN and Bonding

    我们这一节来看Port 一般来说一个Port就是一个Interface,当然也有一个Port对应多个Interface的情况,成为Bond VLAN Configuration Port的一个重要的方 ...

  2. Javascript高级编程学习笔记(25)—— 函数表达式(3)模仿块级作用域

    昨天写了闭包 今天就来聊聊块级作用域的事情 在绝大多数编程语言中,都有块级作用域这个概念 什么是块级作用域呢? 前面我们在刚开始讲的时候说过,JS中的大括号(不在赋值运算符的后面)表示代码块 块级作用 ...

  3. Ubuntu18.04搭建nodejs环境

    首先安装sudo apt install curl 然后安装命令(当前最新版本是0.33.2,最新版本可以在https://github.com/creationix/nvm查看): curl -o- ...

  4. JDK8 新增的日期时间API

    背景 JDK8中增加了一套全新的日期时间API,这里进行总结下,方便查询使用. 新的时间及日期API位于 java.time 包中,下面是一些关键类. Instant:代表的是时间戳. LocalDa ...

  5. 项目文件与 SVN 资源库同步提示错误 Attempted to lock an already-locked dir

    问题描述 之前为了图方便,在eclipse中直接把三个jsp文件复制到了eclipse中我新建的一个文件夹中,把svn版本号信息也带过来了,然后我又删除了这三个jsp文件,接着先把这三个jsp复制到桌 ...

  6. 一个applicationContext 加载错误导致的阻塞解决小结

    问题为对接一个sso的验证模块,正确的对接姿势为,接入一个 filter, 然后接入一个 SsoListener . 然而在接入之后,却导致了应用无法正常启动,或者说看起来很奇怪,来看下都遇到什么样的 ...

  7. Ubuntu下安装和使用开源的tts软件Flite

    Flite是什么? Flite是一个小型.快速的TTS系统,是festival的C版本,可用于嵌入式系统,支持WinCE.Palm OS 等. 下载方法: wget http://www.festvo ...

  8. PHP之ThinkPHP框架(数据库)

    PHP是网站后台开发语言,其重要的操作对象莫过于数据库,之前有了解过mysqli和pdo,但ThinkPHP的数据库交互必须使用其特定的封装方法,或者可以认为其是对PHP数据库操作的进一步封装,以达到 ...

  9. 涨姿势:Spring Boot 2.x 启动全过程源码分析

    目录 SpringApplication 实例 run 方法运行过程 总结 上篇<Spring Boot 2.x 启动全过程源码分析(一)入口类剖析>我们分析了 Spring Boot 入 ...

  10. Python入门必学,用Python练习画个美队盾牌

    0 环境 Python版本:3.6.6 操作系统:Mac OS Mojave 10.14.2 1 引言 最近我媳妇每天晚上吃饭时候也拿手机看,上厕所也在看. 看着看着还会笑?WTF?你在干嘛呢? 没错 ...