淘先锋技术网

首页 1 2 3 4 5 6 7

目录

1、jvm类加载机制

2、jvm内存模型

​3、JVM对象创建

1、类加载检查

2、分配内存

3、初始化

4、设置对象头

5、执行

4、内存分配机制


1、jvm类加载机制

类加载器就是根据指定全限定名称将 class 文件加载到 JVM 内存,然后再转化为 class 对象。

四种类加载器:

启动类加载器(Bootstrap ClassLoader):用来加载jre下lib下java核心类库,无法被java程序直接引用。
扩展类加载器(extensions class loader):它用来加载 Java 的扩展库jre下lib下ext目录下的包。Java 虚拟机的实现会提供一个扩展库目录。该类加载器在此目录里面查找并加载 Java 类。
系统类加载器(system class loader):它根据 Java 应用的类路径(CLASSPATH)来加载 Java 类。一般来说,Java 应用的类都是由它来完成加载的。可以通过 ClassLoader.getSystemClassLoader()来获取它。
用户自定义类加载器,通过继承 java.lang.ClassLoader类的方式实现。重写findClass方法

加载:将字节码文件加载到内存
连接
    验证:校验字节码文件的准确性
    准备:给类的静态变量分配内存,并赋予初始值
    解析:将静态方法符号引用转化为直接引用(内存地址)
初始化:将静态变量赋予指定的值,执行静态代码块

双亲委派机制:先判断系统类加载器r是否已经加载过》判断extclassLoader是否已经加载过》

判断启动类加载器是否已经加载过,没有加载过就尝试加载》extclassLoader尝试加载》

appclassLoader加载

源码: 

类加载器收到了类加载的请求,它首先不会自己去加载这个类,而是把这个请求委派给父类加载器去完成,每一层的类加载器都是如此,这样所有的加载请求都会被传送到顶层的启动类加载器中,只有当父加载无法完成加载请求时,子加载器才会尝试去加载类。

为什么设计双亲委派:
》沙箱安全机制:防止篡改核心api
》避免类重复加载

自定义类加载器,打破双亲委派机制:继承 java.lang.ClassLoader,重写loadclass方法,不委托父加载器,但是注意核心类和扩展类还是别用自定义的类加载器。

2、jvm内存模型

 

 3、JVM对象创建

1、类加载检查

执行new指令(new关键、对象克隆、对象序列化等)时,先检查这个指令的参数能否在常量池中定位到类的符号引用,并且检查这个类是否已被加载。如果没有,必须先执行类加载过程。

2、分配内存

对象所需内存大小在类加载完后便可确定,将一块确定大小的内存从堆中划分出来。

划分内存的方法:

        指针碰撞(默认):如果堆中内存绝对规整,所有用过的内存放在一边,空闲的在另一边,中间放着一个指针作为分界点,那分配内存就是把指针向空闲一边挪动一段和对象大小相等的距离。

        空闲列表:如果堆中内存不规整,虚拟机必须维护一个列表记录哪些内存空闲可用,找一块足够大的分配给对象并记录。

分配时并发问题解决:CAS、TLAB(1.8默认,每个线程在堆中预先分配一小块内存)。

3、初始化

虚拟机需要将分配到的内存空间都初始化为零值(不包括对象头)。

4、设置对象头

初始化后,需要对对象进行必要的设置。对象在内存中存储的布局可以分为3块:对象头、实例数据和对齐填充。

对象头包括两部分信息:一部分是存储对象自身的运行时数据,如hashCode、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏西时间戳等。另一部分是类型指针,即对象指向它的类元数据的指针,虚拟机通过这个指针确定这个对象是哪个类的实例。

32位:对象头:mark word(4字节)+类型指针(4字节)=8字节,数组对象对象头:mark word(4字节)+类型指针(4字节)+长度(4字节)=12字节。

 64:对象头:第一行和第二行4+4=8(8*8=64)是mark word,第三行类型指针指针压缩(节省内存)占4字节。

         对象:最后一行4字节为了对齐填充,保证对象所占内存是8字节整数倍。

 对象头:第一行和第二行4+4=8(8*8=64)是mark word,第三行类型指针占4字节

  5、执行<init>

为属性赋值和执行构造方法。

4、内存分配机制