虽说平时开发我们与虚拟机接触不是直接,但是他是我们工作必不可少的,真正时候对它不了解还真是不行。特别在优化方面。下面简单记录学习的内容。
首先上一张图:
一:类加载过程
方法区:用于存储虚拟机加载的类信息、常量、静态变量、是各个线程共享的内存区域。注意:不是类中的方法堆:被各个线程共享的内存,用来存放对象的 也就是new 的对象就是在这里。
虚拟机栈:线程私有的,”栈帧”用于存储局部变量表(包括参数)、操作栈、方法出口等信息。
程序计数器:它的作用是当前线程所执行的字节码的行号指示器。存放在寄存器。
具体分析过程如下:
加载:加载class文件的信息加载到内存中。由硬盘到内存的迁移
链接:1、将加载阶段加载到内存中的二进制数据整合到虚拟机中
2、验证文件格式验证、元数据验证等等。
3、准备为 类 静态 变量分配内存,并将其初始化为 默认值给常量分配内存并设置值
4、解析把类型中的符号引用转换为直接引用。
初始化:为类的 静态变量赋予正确的 初始化值按照 从上到下 下的顺序(<clinit>)
使用:这个阶段就是调用<init>方法实例化出对象来使用了。
卸载:当类使用完了,再也用不到的时候就可以将类卸载了(必须保证所有的实例被GC)。
二:实例Demo,发现编译器收集的顺序是由语句在源文件中出现的顺序所决定的。如下:
package com.dairuijie.demo;
/**
* 父类
* <p>Title: Father</p>
* <p>Description: </p>
* @author dairuijie
* @date 2018年5月20日
*/
public class Father {
{
System.out.println("Father 构造代码块");
}
public Father(){
System.out.println("Father 构造方法");
}
static{
System.out.println("Father 静态代码块");
}
}
package com.dairuijie.demo;
/**
* 测试执行顺序
* <p>Title: Demo</p>
* <p>Description: </p>
* @author dairuijie
* @date 2018年5月20日
*/
public class Singleton extends Father{
private static Singleton singleton = new Singleton();
public static int count1 = 0;
public static int count2;
private Singleton(){
count1++;
count2++;
System.out.println("子类构造方法");
}
{
System.out.println("子类构造代码块");
}
static{
System.out.println("子类静态构造代码块");
}
public static Singleton getInstance(){
if (singleton == null) {
singleton = new Singleton();
}
return singleton;
}
}
package com.dairuijie.demo;
public class Test{
public static void main(String[] args) {
System.out.println("count1="+Singleton.getInstance().count1);
System.out.println("count2="+Singleton.getInstance().count2);
}
}
结果如图: