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");
}
}
类加载过程如图所示:
加载阶段
通过一个类的全限定名称获取该类的二进制字节流。
把该字节流所代表的静态存储结构转换为方法区的运行时数据结构。
内存中生成一个代表该类的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();
}
给出实现接口方法:
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!!!");
}
}
给出继承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);
}
}
给出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();
}
}
运行结果:
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!