首页 > 系统相关 >Java源代码是如何编译,加载到内存中的?

Java源代码是如何编译,加载到内存中的?

时间:2023-08-09 16:12:55浏览次数:37  
标签:Singleton Java instance static jvm 源代码 class 加载

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

标签:Singleton,Java,instance,static,jvm,源代码,class,加载
From: https://www.cnblogs.com/darcy-yuan/p/17616279.html

相关文章

  • Java遍历集合(List,Map)
    遍历ListpublicvoiditeratorList(){List<String>list=newArrayList<>();list.add("a");list.add("b");//方法1使用iterator遍历Iterator<String>iterator=list.iterator();w......
  • netty_2、Java NIO
    参考:NIO详解(Java):https://juejin.cn/post/6844903605669986317ByteBuffer(内存缓冲区):https://blog.csdn.net/u010430495/article/details/860871541、NIO基础JavaIO是阻塞的,当用户进行数据读写时,首先会由系统去等待数据准备(查看内核空间中有没有数据),等待内核数据准备......
  • Java入门题-密保验证
    问题:设计一个密保验证,由4位随机字母组成,用户输入验证码验证,一共5次机会重要:随机字母、随机组合、字母分大小写代码:需要引入importjava.util.Random;  importjava.util.Scanner; intVF=0;//用于循环while(VF<5){//规定验证5......
  • 14-ribben-饥饿加载
    Ribbon默认是采用懒加载,即第一次访问时才会去创建LoadBalanceClient,请求时间会很长。而饥饿加载则会在项目启动时创建,降低第一次访问的耗时,通过下面配置开启饥饿加载:ribbon:eager-load:enabled:trueclients:userservice......
  • Java 9 新特性
    Java9新特性模块化系统Java9引入模块化系统的一个原因是为了让Java可以运行在内存有限的场景模块可以导出PublicAPI隐藏内部实现,模块可以依赖其它模块moduletech.ruanjiang.modules.car{requirestech.ruanjiang.modules.engines;exportstech.ruanjiang......
  • Java学习之进制之间的转换
    importjava.util.*;publicclassJinzhi{publicstaticvoidmain(String[]args){/***总结:*二进制转换八进制:每三位转换*二进制转换十六进制:每四位转换*十进制转二进制:除以2取余数,得到的余数进行倒叙展示......
  • excel wps宏编辑器,用JavaScript自定义函数设置单元格符合条件后,那一行都变色
        functionjudge(){varapp=Application;//WPS表格的应用程序对象varwb=app.ActiveWorkbook;//当前工作簿varsheet=wb.ActiveSheet;//当前工作表vardataRange=sheet.UsedRange;//使用的数据范围varnumRows=dataRange.Rows......
  • 【javascript】关于 AbortController
    相关概念:https://developer.mozilla.org/zh-CN/docs/Web/API/AbortController需求描述:后台返回10000条图片url,前端拿到后需要做成假分页,假设1页显示20张图,分成50页。部分逻辑:1for(leti=0;i<imgUrlList.length;i++){2letimage=newImage()3image.src=imgUrlLi......
  • maven 依赖的版本号、配置文件修改以后加载不到
    依赖的版本号、配置文件中的配置项不断变化,因此特别适合使用Mavenreimport。2、在项目初期使用,随着项目的不断开发,引入的各种新依赖会很多,频繁的去手动导入数据,使用Mavenreimport可以极大的提高开发效率。  可以使用以下 maven===>Reimport导入 ......
  • java-vector-tile | 使用java生成Mapbox矢量图块规范的矢量图块
    https://github.com/ElectronicChartCentre/java-vector-tile/tree/master/src/main/java/no/ecc/vectortile使用java生成mapbox-gl可读的vectortile......