以前学JVM的时候看过《深入理解JVM》,当时看的很模糊也记了些笔记,更像是为了应付面试。事实是确实把笔记都背上了,春招找实习的时候,内存管理、类加载、垃圾回收三连背一遍。后来自己做项目的时候,涉及到JVM的部分还是不怎么理解,最近重读了上面的书并且看了一些技术大佬的专栏,用博客记录下自己学习过程与思考。

本篇文章关注两个问题:

  1. Java字节码是什么?Java源代码怎么变成Java字节码的?

  2. Java字节码进入JVM后是怎么存储的?

  为了解释上面问题,假设现在我们有一个Main类,调用compute方法执行计算操作,代码如下:

public class Math {
public static final Integer CONSTANT = 10; public int compute() {
int a = 1;
int b = 2;
int c = (a + b) * 10;
return c;
} public static void main(String[] args) {
Math math1 = new Math();
Math math2 = new Math();
math1.compute();
math2.compute();
}
}

对于第一个问题: Class文件是一组以8位字节位基础的单位的二进制流,下图就是显示了如何生成字节码文件。

使用Sublime Text查看Math.class,图片只截取了部分,编辑器是使用16进制显示的。为了方便查看,我们使用 javap -c 指令对代码进行反汇编,就可以得得到可读性更强的文件。

  那么Class文件被加载后在JVM中是如何存储的呢?我们以 HotSpot VM为例,这是目前使用最广泛的Java虚拟机。虚拟机主要由类装载子系统、运行时数据区和执行引擎三部分组成。JVM内存模型将运行时数据区分为五个部分,下面图中其中紫色部分是线程私有的,黄色是线程公有的。我们对着字节码文件详细的解释下这个5个部分分别存放的是什么。

  又叫做线程栈,生命周期与线程相同。栈主要由局部变量表、操作数栈、动态链接、方法出口组成。当main方法运行时JVM会在栈内存区域给主线程分配一块内存,main方法和compute方法执行时,会创建单独的栈帧用于存储方法的一些信息。配合着字节码来说明:

  • 局部变量表:存放的是方法在执行时各种基本类型和引用类型变量,以及returnAddress类型(指向了一条字节码指令的地址);
  • 方法出口:保存的是方法执行完后回到主线程的哪个位置。对于main栈帧,局部变量表里的math变量存放的是堆内存中math变量的地址。
  • 操作数栈:临时存放方法执行时的变量
  • 动态链接:Class 文件中存放了大量的符号引用,这些符号引用指向的是方法。程序运行期间调用方法时,根据运行时常量池的参数,静态符号引用变成直接引用;对象头里的指针会动态的找到方法区中存储的调用方法的信息。

程序计数器:记录的是字节码指令正在执行或者即将执行的行号。

本地方法栈:作用和虚拟机栈类似,为native修饰的方法服务。

方法区:JDK1.8及以后称为元空间,存储被虚拟机加载的类信息、常量、静态变量等。1.8以后方法区使用的是本机的内存。

堆:堆是JVM内存模型中最大的一块,虚拟机启动时就会创建,存储的是大部分对象。

整个代码的执行流程在JVM内存中是这样的,不作更详细的解释了,关键信息在图中已标明。

参考资料:《深入理解Java虚拟机》第二版 周志朋

     《深入拆解Java虚拟机》郑雨迪

     《JVM虚拟机底层原理分析与性能调优》程序员诸葛

最新文章

  1. 在xib中用KVC修改控件属性
  2. PHP 之 this self parent static 对比
  3. Wrangle – 响应式的,触摸友好的多选插件
  4. forEach 方法 (Array) (JavaScript)
  5. 2016.8.16 HTML5重要标签及其属性学习
  6. 修改Broforce无限人数,死亡不减反加
  7. C语言回滚(一)
  8. JS瀑布流布局模式(1)
  9. php nginx fastdfs 下载文件重命名
  10. Java调用Oracle存储Package
  11. solrcloud(solr集群版)安装与配置
  12. Three.js学习笔记02
  13. 对抗生成网络-图像卷积-mnist数据生成(代码) 1.tf.layers.conv2d(卷积操作) 2.tf.layers.conv2d_transpose(反卷积操作) 3.tf.layers.batch_normalize(归一化操作) 4.tf.maximum(用于lrelu) 5.tf.train_variable(训练中所有参数) 6.np.random.uniform(生成正态数据
  14. MySQL中实现DROP USER if EXISTS `test`,即创建新用户时检测用户是否存在
  15. Linux 常用环境变量
  16. Docker生产实践(六)
  17. iOS网络加载图片缓存与SDWebImage
  18. Spark-Streaming总结
  19. linux主机名莫名其妙变成了bogon,并解决修改为localhost
  20. 数论 - SGU 105 DIV3

热门文章

  1. Java实现 LeetCode 222 完全二叉树的节点个数
  2. Java实现最大流量问题
  3. LeetCode 76,一题教会你面试算法时的思考套路
  4. Python Opencv-contrib Camshift&kalman卡尔曼滤波&CSRT算法 目标跟踪实现
  5. 【优雅写代码系统】springboot+mybatis+pagehelper+mybatisplus+druid教你如何优雅写代码
  6. 关于一个服务和api监控的界面,涉及ajax-jsonp,promise应用
  7. Jenkins入门教程(一):Windos下Jenkins的安装教程
  8. @atcoder - AGC024F@ Simple Subsequence Problem
  9. springboot整合oss
  10. python中的importlib包