1.前言

相信许多开发同学看过《深入理解java虚拟机》,也阅读过java虚拟机规范,书籍和文档给人的感觉不够直观,本文从一个简单的例子来看看jvm是如何工作的吧。

本文所有操作均在mac上进行。

2.示例代码

示例代码采用最常见的双重检索单例模式:

package interview.desginpattern.singletion.doublecheck;

import java.io.Serializable;

public class Singleton implements Serializable {
private static volatile Singleton instance = null; private Singleton() {
} public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
} return instance;
}
}

3.指令

经过编译后,我们得到class文件,然后用javap命令查看相关指令

javap -c Singleton:

public class interview.desginpattern.singletion.doublecheck.Singleton implements java.io.Serializable {
public static interview.desginpattern.singletion.doublecheck.Singleton getInstance();
Code:
0: getstatic #2 // get static instance
3: ifnonnull 37 // instance is null,jump 37
6: ldc #3 // push class Singleton to operand stack
8: dup // Duplicate the top (class Singleton) operand stack value
9: astore_0 // Store reference(class Singleton) into local variable
10: monitorenter // synchronized start
11: getstatic #2
14: ifnonnull 27 // instance is null,jump 27
17: new #3 // new class interview/desginpattern/singletion/doublecheck/Singleton
20: dup
21: invokespecial #4 // Method "<init>":()V
24: putstatic #2
27: aload_0 // Load reference (class Singleton) from local variable
28: monitorexit // synchronized end
29: goto 37
32: astore_1
33: aload_0
34: monitorexit // synchronized end (exception)
35: aload_1
36: athrow // throw exception
37: getstatic #2
40: areturn
Exception table:
from to target type
11 29 32 any
32 35 32 any static {}; // static code
Code:
0: aconst_null // Push the null object reference onto the operand stack
1: putstatic #2 // set static instance
4: return
}

有以下几点需要说明:

  • operand stack 即操作数栈,区别于jvm虚拟机栈,是属于栈帧(frame)中的数据结构
  • local variable 即本地变量,也属于栈帧中的结构
  • synchronized 被解析成monitorenter 和 monitorexit两条指令,并且需要处理异常情形

我们知道一般来讲jvm 运行时数据包括,pc寄存器,stack(虚拟机栈),heap,method area, 运行时常量池,本地方法栈。stack 中的每一帧包括,operand stack, local variable , 和指向常量池的指针。

4.class文件

上一节中只是展示了java代码编译成class文件,包含了哪些指令,但是class文件包含的信息远远不止这些。

我们在IDEA 中使用插件 jclasslib bytecode viewer 查看 class文件具体包含哪些信息:

4.1.一般信息

这里省略了class 文件的魔法数标志,0xCAFEBABE

4.2.接口和字段

4.3.方法

  • <init> 方法对应Singletion的构造方法
  • <clinit> 方法对应Singletion.class的构造方法

我们还可以查看getInstatnce编译后的指令 (chapter 3):

4.4.常量池

上述数据结构(4.1, 4.2, 4.3)不会存字符串字面量,而是指向常量池的引用:

4.5.属性

5.加载

加载即根据class文件创建对象/接口.

有两种加载器,分别是bootstrap class loader,和user-defined class cloader,我们可以自定义加载器,比如从网络,或者从加密的class文件中加载对象。

任何一个class/inteface 被限定名 + 类加载器唯一确定,所以jvm实现者在并发的情况下需要确保此唯一性约束。

一般而言,加载流程如下

  1. 看该文件有没有被对应的加载器进行加载
  2. 验证该文件是不是class文件,major or minor version 是否被支持
  3. 检查父类是否被加载
  4. 检查接口是否被加载

6.链接(验证,准备,解析)

验证:确保class文件结构是否正确,是否打破jvm规范

准备:给class或者interface的静态属性设置默认值(区别于显式赋值)

解析:给 symbolic references 赋予确定的值(除了 invokedynamic,其他都可以唯一确定

7.初始化

初始化:调用class或者interface的<init>, <cinit> 方法 (4.3)

8.总结

本文概述了java代码是如何加载到jvm中的,jvm有各种不同的实现(我们最熟悉的hotspot虚拟机),其中细节可能不尽相同。加载到jvm中并不代表程序生命周期的结束,运行时的情况也值得关注。

9.参考

https://docs.oracle.com/javase/specs/jvms/se8/jvms8.pdf

Java源代码是如何编译,加载到内存中的?的更多相关文章

  1. 深入浅出JVM(一):你写得.java文件是如何被加载到内存中执行的

    众所周知,.java文件需要经过编译生成.class文件才能被JVM执行. 其中,JVM是如何加载.class文件,又做了些什么呢? .class文件通过 加载->验证->准备->解 ...

  2. java动态编译类文件并加载到内存中

    如果你想在动态编译并加载了class后,能够用hibernate的数据访问接口以面向对象的方式来操作该class类,请参考这篇博文-http://www.cnblogs.com/anai/p/4270 ...

  3. iOS图片加载到内存中占用内存情况

    我的测试结果: 图片占用内存   图片尺寸           .png文件大小 1MB              512*512          316KB 4MB              10 ...

  4. 想要配置文件生效 需要通过添加到web.xml加载到内存中

    想要配置文件生效 需要通过添加到web.xml加载到内存中

  5. Tomcat启动时加载数据到缓存---web.xml中listener加载顺序(例如顺序:1、初始化spring容器,2、初始化线程池,3、加载业务代码,将数据库中数据加载到内存中)

    最近公司要做功能迁移,原来的后台使用的Netty,现在要迁移到在uap上,也就是说所有后台的代码不能通过netty写的加载顺序加载了. 问题就来了,怎样让迁移到tomcat的代码按照原来的加载顺序进行 ...

  6. gensim Word2Vec 训练和使用(Model一定要加载到内存中,节省时间!!!)

    训练模型利用gensim.models.Word2Vec(sentences)建立词向量模型该构造函数执行了三个步骤:建立一个空的模型对象,遍历一次语料库建立词典,第二次遍历语料库建立神经网络模型可以 ...

  7. 把資源加载到内存中 BMP 出错

    BMP文件放到VS的資源中時,VS會將BMP的文件頭去掉,即BITMAPFILEHEADER,這個結構體去除.所以當加載BMP到內存中時,如果是使用GDI+或是其它解釋庫時,會解析失敗. 所以在讀取B ...

  8. Java程序设计19——类的加载和反射-Part-A

    1 本文概要 本章介绍Java类的加载.连接和初始化的深入知识,并重点介绍Java反射相关的内容.本章知识偏底层点,这些运行原理有助于我们更好的把我java程序的运行.而且Java类加载器除了根加载器 ...

  9. Java基础_类的加载机制和反射

    类的使用分为三个步骤: 类的加载->类的连接->类的初始化 一.类的加载 当程序运行的时候,系统会首先把我们要使用的Java类加载到内存中.这里加载的是编译后的.class文件 每个类加载 ...

  10. 你知道 Java 类是如何被加载的吗?

    前言 最近给一个非 Java 方向的朋友讲了下双亲委派模型,朋友让我写篇文章深度研究下JVM 的 ClassLoader,我确实也好久没写 JVM 相关的文章了,有点手痒痒,涂了皮炎平也抑制不住的那种 ...

随机推荐

  1. 文心一言 VS chatgpt (15)-- 算法导论3.2 4~5题

    四.函数 $\lceil \lg n \rceil !$ 多项式有界吗?函数 $\lceil \lg \lg n \rceil !$ 多项式有界吗? 文心一言: chatgpt: 对于第一个问题,函数 ...

  2. 2022-06-27:给出一个长度为n的01串,现在请你找到两个区间, 使得这两个区间中,1的个数相等,0的个数也相等, 这两个区间可以相交,但是不可以完全重叠,即两个区间的左右端点不可以完全一样。

    2022-06-27:给出一个长度为n的01串,现在请你找到两个区间, 使得这两个区间中,1的个数相等,0的个数也相等, 这两个区间可以相交,但是不可以完全重叠,即两个区间的左右端点不可以完全一样. ...

  3. 2021-12-13:字符串解码。给定一个经过编码的字符串,返回它解码后的字符串。 编码规则为: k[encoded_string],表示其中方括号内部的 encoded_string 正好重复 k

    2021-12-13:字符串解码.给定一个经过编码的字符串,返回它解码后的字符串. 编码规则为: k[encoded_string],表示其中方括号内部的 encoded_string 正好重复 k ...

  4. Prompt learning 教学[技巧篇]:通过增加示例、引导词、特殊符号指令等方式让chatgpt输出更好的答案

    Prompt learning 教学[技巧篇]:通过增加示例.引导词.特殊符号指令等方式让chatgpt输出更好的答案 技巧1:To Do and Not To Do 在问答场景里,为了让 AI 回答 ...

  5. Django context must be a dict rather than UserProfile.

    context must be a dict rather than UserProfile. # 主页@login_requireddef index(request): data={} data ...

  6. Vue3.3 的新功能的一些体验

    Vue3 在大版本 3.3 里面推出来了一些新功能(主要是语法糖),网上有各种文章,但是看起来似乎是一样的. 我觉得吧,有新特性了,不能光看,还要动手尝试一下. DefineOptions 宏定义 先 ...

  7. 8张图带你全面了解kafka的核心机制

    前言 kafka是目前企业中很常用的消息队列产品,可以用于削峰.解耦.异步通信.特别是在大数据领域中应用尤为广泛,主要得益于它的高吞吐量.低延迟,在我们公司的解决方案中也有用到.既然kafka在企业中 ...

  8. GPT大语言模型Alpaca-lora本地化部署实践【大语言模型实践一】

    模型介绍 Alpaca模型是斯坦福大学研发的LLM(Large Language Model,大语言)开源模型,是一个在52K指令上从LLaMA 7B(Meta公司开源的7B)模型微调而来,具有70亿 ...

  9. 机器学习数据顺序随机打乱:Python实现

      本文介绍基于Python语言,实现机器学习.深度学习等模型训练时,数据集打乱的具体操作. 1 为什么要打乱数据集   在机器学习中,如果不进行数据集的打乱,则可能导致模型在训练过程中出现具有&qu ...

  10. 洛谷P3368 【模板】树状数组 2-(区间修改,单点查询)

    题目描述 如题,已知一个数列,你需要进行下面两种操作: 将某区间每一个数加上 x: 求出某一个数的值. 输入格式 第一行包含两个整数 N.M,分别表示该数列数字的个数和操作的总个数. 第二行包含 N  ...