• Java JVM生命周期、动态代理——Java JVM筑基



    虚拟机启动

    Java虚拟机的启动通过引导类加载器bootstrap class loader,创建一个初始类initial class来完成的,这个类由Java虚拟机具体实现指定。


    虚拟机的执行

    • 一个运行的Java虚拟机有一个非常清晰的任务:执行Java程序
    • 程序开始执行虚拟机才会运行,程序结束虚拟机结束。
    • 执行一个所谓的Java程序的时候,真真正正执行的是一个叫做Java虚拟机的进程。

    虚拟机的退出

    如下情况:

    • 程序正常执行并且结束。
    • 程序执行过程遇到了exception或者error从而异常终止。
    • 由于OS系统调用出现错误导致Java虚拟机进程终止。
    • 线程调用runntime或者system类方法的exit方法,或者Runntime类的halt方法,并且Java安全管理器允许这次exit或者halt操作。
    • 除上述情况之外,JNI规范描述了JNI invocation API加载或者卸载Java虚拟机时,Java虚拟机退出的情况。

    Java对象头

    在JVM中,对象在内存中的布局分为三部分:对象头、实例数据和对齐填充
    在这里插入图片描述

    synchronized同步锁就是存储在Java对象头里面的。

    Java虚拟机HotSpot有两种对象头:

    • 数组类型,若对象是数组类型,则虚拟机时3个字节宽度(Word)存储对象头。
    • 非数组类型,若对象是非数组类型,则2个word字宽存储对象头。

    对象头由两个部分构成:

    • MarkWord:存储自身的运行时数据,例如HashCode、GC年龄,锁相关信息。
    • KlassPointer:类型指针指向了它的类元数据指针。

    64位虚拟机的MarkWord是64bit,运行期间,MarkWord存储的数据会随着锁标志位变化而变化。

    在这里插入图片描述


    Dalvik VM

    Google开发的应用于Android系统,并且提供了JIT,发展迅猛。
    Dalvik只能称为虚拟机,不可以被叫做Java虚拟机,因为其没有遵循Java虚拟机规范,不可以直接执行Java的class文件。

    基于寄存器架构,不是JVM的栈结构。

    执行的是编译之后dex文件,执行效率高:

    • 其执行的dex文件可以通过class文件转换而来,使用Java语法编写的app,可以直接使用大部分的Java API等等。

    Android 5.0支持提前编译AOT的ART VM替换Dalvik VM。


    类加载子系统

    概述

    在这里插入图片描述

    在这里插入图片描述

    若想要手写JVM虚拟机,则需要考虑如下两点:

    • 类加载器
    • 执行引擎

    类加载器子系统的作用意义

    类加载器子系统负责从文件或者网络加载class文件,class文件在文件开头有特定的文件标识。

    classLoader只负责class文件的加载,至于是否可执行,则是由Exceution Engine来决定。

    加载的信息存放于一块称之为方法区的内存空间,至于是否可运行。除了类信息之外,方法区存放运行时候的常量池信息。可能包括字符串字面常量和数字常量(这部分常量信息是Class文件常量池部分的内存映射)。
    在这里插入图片描述

    • classFile存放于本地硬盘,可以当作图纸模板,该模板在执行的时候加载到JVM当中根据该文件实例化出N个一摸一样的实例。
    • classFile加载到JVM中,称之为DNA元数据模板,存放于方法区。
    • 在.class文件 ==> JVM ==> 最终成为一个元数据模板,这个过程需要一个运输的工具,也就是类加载器,扮演快递的角色任务。

    在这里插入图片描述


    类加载的过程

    给出简单代码:

    public class Loader {
    	public static void main(String[] args) {
    		System.out.println("I have been class loader");
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    类加载过程如图所示:

    在这里插入图片描述


    加载阶段

    通过一个类的全限定名称获取该类的二进制字节流。

    把该字节流所代表的静态存储结构转换为方法区的运行时数据结构。

    内存中生成一个代表该类的java.lang.class对象,并且作为该方法区的各种数据访问入口。


    加载class文件的方式

    • 本地系统直接加载。
    • 网络获取,例如:Web applet
    • zip压缩包读取,成为日后jar、war格式的基础。
    • 运行时计算生成,例如:动态代理技术
    • 其他文件生成,典型场景:JSP应用从专有的数据库中提取.class文件
    • 加密文件获取,典型的防止class文件被反编译的保护措施。

    补充:代理模式

    代理模式:给某一个对象提供一个代理,并由代理对象负责控制真实对象的访问。代理模式是一种结构型设计模式

    代理模式角色分为三种:

    • Subject抽象主题角色:定义代理类和真是主题的公共对外方法,也就是代理类的真实主题的方法。
    • RealSubject真实主题角色:真正意义上实现业务逻辑的类。
    • Porxy代理主题角色:用来代理和封装真实的主题。

    代理模式结构简单,核心在于代理类,为了实现让客户端实现一致性对待真实对象和代理对象,在代理模式中引入了抽象层。

    在这里插入图片描述

    代理模式按照指责分类,如下所示:

    • 远程代理。
    • 虚拟代理。
    • Copy-On-Write代理。
    • 保护Protect or Access代理。
    • 同步化synchronized代理。
    • 智能引用Smart Reference代理。

    根据字节码class创建时机分类,可以分为静态代理和动态代理:

    • 所谓静态也就是在程序运行前就已经存在代理类的字节码文件,代理类和真实主题角色的关系在运行前就确定了。
    • 动态代理就是源码是在程序运行期间由JVM根据反射机制等动态生成,运行前不存在所谓的代理类字节码文件。

    代理实例

    给出Girl接口:

    package proxyTest;
    
    public interface Girl {
    	void date();
    
    	void watchMovie();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    给出实现接口方法:

    package proxyTest;
    
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    public class wang implements Girl {
    
    	@Override
    	public void date() {
    		// TODO Auto-generated method stub
    		SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd 'at' HH:mm:ss z");
    		Date date = new Date(System.currentTimeMillis());
    		System.out.println("约会日期: " + format.format(date));
    	}
    
    	@Override
    	public void watchMovie() {
    		// TODO Auto-generated method stub
    		System.out.println("lets got to watching movie!!!");
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    给出继承invocation的wangProxy:

    package proxyTest;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    public class wangProxy implements InvocationHandler {
    
    	private Girl girl;
    
    	/**
    	 * @Title: wangProxy
    	 * @Description: TODO(这里用一句话描述这个方法的作用)
    	 * @param: @param girl
    	 * @author: mac
    	 * @throws
    	 */
    	public wangProxy(Girl girl) {
    		super();
    		this.girl = girl;
    	}
    
    	@Override
    	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    		// TODO Auto-generated method stub
    		doSomeThingBefore();
    		Object obj = method.invoke(girl, args);
    		doSomeThingEnd();
    		return obj;
    	}
    
    	private void doSomeThingEnd() {
    		// TODO Auto-generated method stub
    		System.out.println("your bill is allright, you can enjoy your movie now!");
    	}
    
    	private void doSomeThingBefore() {
    		// TODO Auto-generated method stub
    		System.out.println("before start watch, we need to check your bill");
    	}
    
    	public Object getProxyInstance() {
    		return Proxy.newProxyInstance(girl.getClass().getClassLoader(), girl.getClass().getInterfaces(), this);
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    给出main实现代理:

    package proxyTest;
    
    public class ListenWang {
    
    	public static void main(String[] args) {
    		// TODO Auto-generated method stub
    		// 隔壁有个女孩
    		Girl girl = new wang();
    		// 通过代理实现访问
    		wangProxy family = new wangProxy(girl);
    		Girl friend = (Girl) family.getProxyInstance();
    		// 实现方法
    		friend.date();
    		System.out.println("=======================");
    		friend.watchMovie();
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    运行结果:

    before start watch, we need to check your bill
    约会日期: 2022-08-22 at 16:17:13 CST
    your bill is allright, you can enjoy your movie now!
    =================================================
    before start watch, we need to check your bill
    lets got to watching movie!!!
    your bill is allright, you can enjoy your movie now!
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
  • 相关阅读:
    《向量数据库指南》——AI原生向量数据库Milvus Cloud 2.3新功能
    亚马逊卖家参与活动:提升产品排名的神秘法宝?
    学习文档1
    入行3D建模难不难学习?10年建模师:这3种人,一辈子都学不会
    22.app.js的全局数据共享
    卷积神经网络(CNN)识别验证码
    geo 读取单细胞csv表达矩阵 单细胞 改列名 seurat
    JavaScript中this关键字
    AWS实战(一)-创建S3 存储桶
    Java设计模式——模板方法模式
  • 原文地址:https://blog.csdn.net/qq_42544728/article/details/126465937