一流程序员与二流程序员的分水岭:JVM虚拟机-全面理解

萨瓦迪卡10个月前 (09-22)jvm7032

秉承一个信念,要学遍学底层逻辑。那是一通百通的底气。

一、学不学JVM 是自主解决问题的一流程序员与跟着别人做CRUD的二流程序员的分水岭。只有深入了解透彻jvm的工作过程及原理,才能对自己开发出高性能的代码充满信心。

二、JVM虚拟机的本质将class文件转换成操作系统具体的指令。
一个java文件从编写到执行的过程:通过javac将java文件编译成一个class文件交给虚拟机,虚拟机的工作过程如图:


d486157c-7b0e-44f5-a572-119c6318f819.png

1首先就是将classFile文件通过类加载(ClassLoader也就是个类)加载到jvm虚拟机的内存中。就是将类加载到就是方法区(元数据区)

2然后交给执行引擎,将类中指令解析出来执行,执行过程中会将类创建对象。

3再将对象创建到堆当中。

那要执行某个东西需要一个逻辑就是线程。因为只有线程是执行程序的唯一单元。在jvm内部,会对每一个线程分配一个虚拟机栈(左数第2列),它是一个先进后出的栈结构。在这个栈里面会记录当前线程运行的所需要的数据。


栈(线程):存放局部变量。只要有一个线程运行主方法,jvm马上会在线程栈内一大块内存 给当前线程分配一小块独立的内存空间,用来放线程运行中 这些局部变量。(一个线程内有多个方法)
虚拟机栈(线程私有)核心包括:
   栈帧(会为每个方法创建一个专属的内存空间,也就是创建一个栈帧,它把一个线程内的不同的方法内存给隔离开来),栈帧又包含:
局部变量表:存放每个方法里的局部变量
        操作数栈:就是我们的操作数,在程序运行过程中它要做操作的临时的中转 存放的内存空间
局部变量表和操作数栈,这两个是执行java文件最基础的数据结构,记录我要执行这个方法需要多少的内存。局部变量对应的操作数。
        动态链接库:是指向方法区的哪个方法
动态链接是:把符号引用 (常量池的符号)转为 直接引用 (直接地址)。这些符号,程序加载的时候不会解析,main方法会解析,但方法  是在程序运行的时候 需要找到这些符号的代码       (把这些符号转换成代码的直接内存地址)  解析的。这就是调动态链接。)
         返回地址(方法出口):执行完返回到哪里
方法出口:方法执行完,要回到哪个地方去。比如:main()里的,Math math = new Math();一般来说new一个对象是放在堆里面,那main()的局部变量表是 有个math的,这个math存的是给他分配的对象在堆里面内存地址。)
附加信息:jvm自己实现时附带的信息。

   每一个线程中都有一个 程序计数器:记录当前线程运行到哪一步了。


执行引擎:具体执行过程中,后很多执行方式,包括:解释执行、编译执行。编译执行又分为C1和C2(默认)两种。

类在元数据区,对象在堆区。
栈和堆的关系:栈里面有很多的局部变量, 栈里面放的都是这些对象在堆里面的内存地址。
方法区和堆的关系:我方法区如果有很多静态变量,其中有些静态变量是对象,放的是堆里面的内存地址。
栈、本地方法栈、程序计数器,是每个线程独有的。

堆和方法区 是所有的线程共享的内存区域。


image.png

堆:分为年轻代、老年代。对象一般会放在eden区。

假设有一个web7*24小时运行,当堆里eden区对象放满的时候,会触发垃圾收集gc(minor gc ):就是把无用的对象回收一下。找到非垃圾对象,放到survior区,剩下的干掉。如果一个对象经历过一次gc之后,分代年龄会加1.当分代年龄加到15,会被挪到老年代。


如果老年代放满了,它会触发full gc,它回收的是整个堆以及方法区。那如果有些老年堆里的对象被gc root引入了,回收不了,那就没有新的空间放新的对象,这时会触发OOM.在整个gc的过程中,可能会触发一个 STW机制(stop the word),停止用户线程。STW就是在gc时,会停掉用户的所有线程。用户会感到卡顿了一下,那SWT会对网站的性能有一定的影响的。


什么样的对象最终会别挪到老年代?静态变量对象、缓存对象、spring容器内的对象。

JVM的主要目的就是减少full gc,或者是减少full gc 的时间。因为在full gc的时候收集堆的时间比较长,所以它STW的时间相对也比较长。当然也要减少minor gc的次数。


二、Class 文件规范

1、Class文件结构

实际上,我们需要了解的是,Java 官方实际上只定义了JVM的一种执行规范,也就是class文件的组织规范。理论上,只要你能够写出一个符合标准的class文件,就可以丢到 JVM 中执行。至于这个class文件是怎么来的,JVM 虚拟机是不管的。这也是 JVM 支持多语言的基础。
这个规范到底是什么样子呢?当然,你可以直接去看 Oracle 的官方文档。JDK8 的文档地址:https://docs.oracle.com/javase/specs/jvms/se8/html/index.html 。后面也会有文章详细分析每一个字节。这里,我们只抽取主体内容。
比如,对于一个ByteCodeInterView.class文件,可以用 UltraEdit 工具打开一个class文件,看到的内容部分是这样的:

6d7ad69d-9884-463a-b89d-84fd381a0b6b.png

中间这一部分就是他的二进制内容。当然这是十六进制的表达。空格隔开的部分代表了 8 个bit,而每一位代表的是 4 个 bit字节,也就是一个十六进制的数字。例如 第一个字母 C 就表示十六进制的 12二进制是 1100。而所有的class文件,都必须以十六进制的 CAFEBABE 开头,这就是 JVM 规范的一部分。这也解释了 Java 这个词的由来,到底是一种咖啡,还是爪哇岛。

Spring6及springboot3已经用到jdk17了,但是我们jdk8 是跑不起来spring6的。

后面的部分就比较复杂了,没法直接看。可以用 javap指令可以直接来看一些class文件。比如:

b1b8939c-e33d-4fe1-aaa0-bc7815e81692.png

还是不容易查看或看懂,可以安装并使用插件:jclasslib Bytecode viewer图形化查看:

950429fd-f774-4ab9-aef7-bbe18e9a6f19.png

可以看到jvm的字节码,以及整个的执行过程:

6397a883-696f-494c-a12b-fdfa96d48ccc.png6397a883-696f-494c-a12b-fdfa96d48ccc.pngd9003aee-6ee3-4f2b-93ce-6231b23bbbe0.png

再就是LineNumbertable这里,说明第10行代码执行的 0到6的指令。

image.png

本文原创,转载必追究版权。

分享给朋友:

相关文章

 程序员的中秋礼物.......

程序员的中秋礼物.......

【小姐你好,我是程序员】“小姐你好,我是程序员。”女生礼貌地回答:“你好,程先生。”男:“……哦,叫我序员就可以了。”   【程序员的愿望】有一天一个程序员见到了上帝。上...

开机密码忘记怎么办

1、重新启动计算机,在启动画面出现后马上按下F8键(不同类型型号电脑启动键不一样,参考附加),选择“带命令行的安全模式”。2、运行过程结束时,系统列出了系统超级用户“administrator”和本地...

MyEclipse 中项目修改SVN的地址

MyEclipse 中项目修改SVN的地址

在工作环境调整时,有的时候SVN服务器的地址需要修改,而正在开发中的项目在Eclipse中有些代码没有提交,此时怎么修改SVN的地址呢?以下有一个简单的办法:一、在MyEclipse中选择Window...

樊山越玲 一周年

樊山越玲 一周年

2015-12-25樊先森:周末有约吗?玲玲:有约,不过也得先以你为主啊。樊先森:昂,这样说我还挺开心的。2015-3-26玲玲:亲爱的,苹果是你买的吗?已经收到了,谢谢老公玲玲:有点小惊喜樊先森:那...

mysql 建存储过程 实例

drop PROCEDURE if EXISTS sp_lasqCREATE PROCEDURE sp_lasq()    COMMENT '超过5天自动立案&#...

ajax提交表单、ajax实现文件上传(multipart/form-data)

方式一:利用from表单的targer属性 + 隐藏的iframe 达到类似效果, 支持提交含有文件和普通数据的复杂表单方式二:使用jquery的$.ajax({..}), 支持提交普通表单,但不支持...

评论列表

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。