对象的创建过程:
- 当虚拟机遇到一个new的指令时,首先根据这个指令所带的类参数 去方法区的常量池寻找类的符号引用,能找到说明存在这个类。
- 验证符号引用所代表的类是否完成类加载
- 为新生对象分配内存(所需内存大小来类加载时完成确定)
分配内存的两种方式
- 指针碰撞:将临界点指针移动一个对象大小的距离即可完成分配
- 空闲列表:虚拟机维护着一个记录空闲内存的地址表,分配时遍历该表,直到找到第一个比对象所需内存大的内存区域。即可完成分配。并更新该表。
当Java堆规整的情况下,使用指针碰撞方式分配内存
当Java堆不规整时,使用空闲列表方式
Java堆是否规整取决于所采用的垃圾收集器是否具有压缩整理的功能
分配内存时的线程安全问题:
问题描述:当多个线程同时请求分配内存时,有可能找到同一个地址块。当线程A完成分配后,还未更新 空闲列表 时,线程B请求分配。
问题解决:
方案一:同步整个空闲列表,使用CAS锁
方案二:本地线程分配缓冲。在Java堆中为每个线程开辟一小块内存区域,每个线程先在各自线程内部分配区域,互不干扰。当本地线程分配缓冲耗尽时,采用方案一。
类加载过程:
加载 --> 验证 --> 准备 --> 解析 --> 初始化 --> 使用 --> 卸载
其中 验证 准备 解析的都属于链接阶段
加载:
- 根据类的全限定名获取定义该类的二进制字节流文件 (一般是class文件,其他类型文件也可以)
- 将二进制字节流按照虚拟机规范格式存储在方法区中 ,实际上时将静态的存储结构转换为方法区的运行时数据结构
- 在方法区生成一个Java.long.class对象。作为方法区中该类的各种数据的访问入口
验证:
确保字节流中包含的信息符合虚拟机规范,并不会影响到虚拟机安全
- 文件格式验证:
- 元数据验证:
- 字节码验证:
- 符号引用验证:
准备:
为类变量(static静态变量)分配内存并初始化值的过程。
解析:
虚拟机将常量池中符号引用改为直接引用的过程。
解析主要针对:类或接口、字段、类方法、接口方法、方法类型、方法句柄、调用点限定符 这七类符号引用。
初始化:
按照程序员计划初始化变量和其他资源的过程
理解:执行静态代码块、代码块、构造方法的过程。
类加载器:
作用:把由javac编译成的class文件,装进虚拟机。
分类:
- 启动类加载器(bootstrap classloader):加载<JAVA_HOME>/lib 目录下类库中的Java类
- 扩展类加载器(extension classloader):加载<JAVA_HOME>/lib/ext 目录中的 扩展类
- 应用程序类加载器(application classloader):当前工作目录/bin 中的用户类
双亲委派模型
- 当一个类加载器接收到类加载任务时,先查缓存里有没有,如果没有,将任务委托给它的父加载器去执行。
- 父加载器也做同样的事情,一层一层往上委托,直到最顶层的启动类加载器为止。
- 如果启动类加载器没有找到所需加载的类,便将此加载任务退回给下一级类加载器去执行,而下一级的类加载器也做同样的事情。
- 如果最底层类加载器仍然没有找到所需要的class文件,则抛出异常。