一个“Hello World”理解JVM运行时数据区
先上一张JVM体系结构图:

1)运行时数据区:经过编译生成的字节码文件(class文件),由class loader(类加载子系统)加载后交给执行引擎执行。在执行引擎执行的过程中产生的数据会存储在一块内存区域。这块内存区域就是运行时区域
2)程序计数器:用于记录当前线程的正在执行的字节码指令位置。由于虚拟机的多线程是切换线程并分配cpu执行时间的方式实现的,不同线程的执行位置都需要记录下来,因此程序计数器是线程私有的
3)虚拟机栈:虚拟机栈是java方法执行的内存结构,虚拟机会在每个java方法执行时创建一个“栈桢”,用于存储局部变量表,操作数栈,动态链接,方法出口等信息。当方法执行完毕时,该栈桢会从虚拟机栈中出栈。其中局部变量表包含基本数据类型和对象引用;
在java虚拟机规范中,对这个区域规定了两种异常状态:如果线程请求的栈的深度大于虚拟机允许的深度,将抛出StackOverFlowError异常(栈溢出),如果虚拟机栈可以动态扩展(现在大部分java虚拟机都可以动态扩展,只不过java虚拟机规范中也允许固定长度的java虚拟机栈),如果扩展时无法申请到足够的内存空间,就会抛出OutOfmMemoryError异常(没有足够的内存)
4)本地方法栈:类似java方法的执行有虚拟机栈,本地方法的执行则对应有本地方法栈
5)方法区:用于存储已被虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码等数据。线程共享(看存储的数据就知道了)
java虚拟机规范对方法区的限制非常宽松,除了和java堆一样不需要连续的内存和可以选择固定大小或者可扩展外,还可以选择不实现垃圾收集。相对而言,垃圾收集在这个区域是比较少出现的,但并非数据进入了方法区就如永久代的名字一样永久存在了。这区域的内存回收目标重要是针对常量池的回收和类型的卸载,一般来说这个内存区域的回收‘成绩’比较难以令人满意。尤其是类型的卸载条件非常苛刻,但是这部分的回收确实是必要的。在sun公司的bug列表中,曾出现过的若干个严重的bug就是由于低版本的HotSpot虚拟机对此区域未完成回收导致的内存溢出。
6)java堆(java Heap):堆的主要作用是存放程序运行过程中创建的对象实例,因为要存放的对象实例有可能会极多,因此也是虚拟机内存管理中最大的一块。并且由于硬件条件有限,所以需要不断回收已“无用”的实例对象来腾出空间给新生成的实例对象;因此java的垃圾回收主要是针对堆进行回收的(还有方法区的常量池),java堆很多时候也被称为GC堆(Garbage Collected Heap)。
7)类加载机制(Class Loader):类加载子系统是根据一个类的全限定名来加载该类的二进制流到内存中,在JVM中将形成一份描述Class结构的元信息对象(方法区),通过该元信息对象可以获知Class的结构信息:如构造函数,属性和方法等,Java允许用户借由这个Class相关的元信息对象间接调用Class对象的功能。
好!说了这么多关键字,再拿例子来讲解一下这些关键字:
A.图1是我们写的HelloWorld.java,通过IDE或命令:javac HelloWorld 编译生成16进制的HelloWorld.class(字节码文件,见图3),想读懂16进制字节可参考:一文让你明白java字节码 ;但一般IDE会自动转译成图2的指令;或者通过命令:javap -verbose HelloWorld 进行转译。
(图1)HelloWorld.java

(图2)HelloWorld.class

(图3)16进制的字节码:

B.接着,当我们通过IDE或者命令:java HelloWorld 运行这个class文件时,字节码文件(class文件)通过类加载机制加载完毕交付给执行引擎执行;类加载机制把HelloWrold类的信息、静态变量(例子中没加)、常量(例子中没加,常量会加载到方法区的常量池,这和静态变量不一样)等加载到方法区中,接下来如果需要创建该类的对象,需要通过new后面带的参数到方法区进行查找类相关信息。
C.类加载完后,虚拟机会检查程序的入口,虚拟机中程序的执行入口为main函数,如HelloWorld.class中,,执行引擎找到main函数开始执行指令,并生成一个“桢栈”入栈至虚拟机栈的栈顶;我们可以看到(图2)在main方法下面的命令:0 new java.lang.StringBuilder [16] 表示创建一个String对象,创建的String对象实例会在java堆(Heap)中分配内存存储(Java对象在JVM中的创建过程可以看这篇文章:Java对象是怎么创建的(通过对象的创建,了解JVM内存结构)),并把该指令位置“0”记录到当前线程的程序计数器中;3 dup 然后把该对象的引用压入虚拟机栈中,并把该指令位置“3”记录到当前线程的程序计数器中;4 ldc <String "Hello"> [18] 从字符串常量池(从jdk1.7开始,字符串常量池被移动到java堆)加载字符串常量Hello,并更新指令位置到程序计数器;...如果执行过程中有本地方法的指令,则会在本地方法栈中进行出入栈;这里有个点注意一下,请看main函数指令16的位置: 16 new java.lang.StringBuilder [31] 这里创建了一个StringBuilder对象,自jdk5开始已对这种类型的字符串拼接进行了优化,具体自行谷歌补充。
D.执行引擎执行指令过程中,按需调用本地库接口以执行本地库方法,如new指令、输出屏幕等操作
以上就是一个HelloWorld执行过程在JVM中发生的事情。
参考:
《深入理解Java虚拟机:JVM高级特性与最佳实践》一书
https://www.cnblogs.com/IUbanana/p/7067362.html
一个“Hello World”理解JVM运行时数据区的更多相关文章
- JVM运行时数据区和垃圾回收机制
最近参考各种资料,尤其是<深入理解Java虚拟机 JVM高级特性和最佳实践>,大牛之作.把最近学习的Java虚拟机组成和垃圾回收机制总结一下. 你不会的都是新知识,学无止境,每天进步一点点 ...
- Jvm运行时数据区
一:运行时数据区 Java虚拟机在执行Java程序的过程中会把它管理的内存分为若干个不同的数据区域.这些区域有着各自的用途,一级创建和销毁的时间,有的区域随着虚拟机进程的启动而存在,有些区域则依赖用户 ...
- Java内存管理:Java内存区域 JVM运行时数据区
转自:https://blog.csdn.net/tjiyu/article/details/53915869 下面我们详细了解Java内存区域:先说明JVM规范定义的JVM运行时分配的数据区有哪些, ...
- JVM 运行时数据区 (三)
JVM运行时数据区 运行时数据区由 程序计数器.java虚拟机栈.本地方法栈.堆.方法区 组成: 1.程序计数器 每一个Java线程都有一个程序计数器,用于保存程序执行到当前方法的哪一个指令,它是线程 ...
- JVM总结(一):概述--JVM运行时数据区
大三下,趁着寒假重温一遍JVM,准备在一个系列来总价一下学习JVM的整个过程.争取在接下来的一个星期内更新完这一个系列,然后回家过年. JVM运行时数据区 线程私有的数据区 程序计数器 虚拟机栈 本地 ...
- JVM运行时数据区与JVM堆内存模型小结
前提 JVM运行时数据区和JVM内存模型是两回事,JVM内存模型指的是JVM堆内存模型. 那JVM运行时数据区又是什么? 它包括:程序计数器.虚拟机栈.本地方法栈.方法区.堆. 来看看它们都是干嘛的 ...
- Java中的字符串常量池和JVM运行时数据区的相关概念
什么是字符串常量池 JVM为了减少字符串对象的重复创建,其维护了一个特殊的内存,这段内存被成为字符串常量池或者字符串字面量池 工作原理 当代码中出现字面量形式创建字符串对象时,JVM首先会对这个字面量 ...
- JVM运行时数据区及对象在内存中初始化的过程
JVM运行时数据区 Java虚拟机所管理的内存区域,也称为运行时数据区,分为以下几个运行时数据区,如图所示 程序计数器:当前程序所执行字节码的行号指示器 程序计数器(Program Counter R ...
- JVM 运行时数据区(二)
@ 目录 运行时数据区 共享区 堆区 方法区 隔离区 虚拟机栈 栈帧 本地方法栈 程序计数器 运行时数据区 JVM 运行时数据区主要分为5块 方法区 JDK1.8以后叫做元数据区(Metaspace) ...
随机推荐
- Go语言基础之文件操作
本文主要介绍了Go语言中文件读写的相关操作. 文件是什么? 计算机中的文件是存储在外部介质(通常是磁盘)上的数据集合,文件分为文本文件和二进制文件. 打开和关闭文件 os.Open()函数能够打开一个 ...
- Failed to execute goal on project e3-manager: Could not resolve dependencies for project cn.e3mall:e3-manager:pom:0.0.1-SNAPSHOT: Could not find artifact cn.e3mall:e3-parent:jar:0.0.1-SNAPSHOT
新建好工程后一定要记得从底层开始clean和install 在启动新建的工程时到最后一步出现了这个问题: Failed to execute goal on project e3-manager-we ...
- MySql(一)_利用NHibernate和MySql交互
1.基础配置,添加MySql和nHibernate的引用 (1) 添加引用,导入MySql.data.dll: 利用MySql提供的API操作: (2) 添加引用,导入NHibernate.d ...
- List<Object> 多条件去重
上一篇将到根据某一条件去重List<Object> 对象链表.本文章根据多条件去重List<Object>去重 private List<StaingMD0010> ...
- Decorator:从原理到实践
前言 原文链接:Nealyang/personalBlog ES6 已经不必在过多介绍,在 ES6 之前,装饰器可能并没有那么重要,因为你只需要加一层 wrapper 就好了,但是现在,由于语法糖 c ...
- 编程必备基础知识|计算机组成原理篇(09):CPU的控制器和运算器
计算机基础方面的知识,对于一些非科班出身的同学来讲,一直是他们心中的痛,而对于科班出身的同学,很多同学在工作之后,也意识到自身所学知识的不足与欠缺,想回头补补基础知识.关于计算机基础的课程很多,内容繁 ...
- Java 从入门到进阶之路(六)
之前的文章我们介绍了 Java 的数组,本章我们来看一下 Java 的对象和类. Java 是一种面向对象语言,那什么是对象呢,对象在编程语言中属于一个很宽泛的概念,我们可以认为万事万物都是对象,每个 ...
- unity - TileMap的注意事项
本文记述了一些在使用Tilemap绘制场景时的需要注意的细节问题. 关于Tilemap的创建及使用本文不做说明,但推荐佳作:Unity中使用Tilemap快速创建2D游戏世界 - feng 本文项目地 ...
- asp.net 开源工作流-流程属性-流程关键字段
关键词:工作流快速开发平台 工作流流设计 业务流程管理 Java工作流引擎 asp.net 开源工作流 net开源工作流引擎 开源工作流系统 定义:业务关键字段也叫流程实例的摘要字段,他提取流程 ...
- 从原理到场景 系统讲解 PHP 缓存技术(全)
概述 缓存已经成了项目中是必不可少的一部分,它是提高性能最好的方式,例如减少网络I/O.减少磁盘I/O 等,使项目加载速度变的更快. 缓存可以是CPU缓存.内存缓存.硬盘缓存,不同的缓存查询速度也不一 ...