java内存模型和类的加载机制

1. JAVA技术体系:
jdk(Java Development Kit ):Java开发工具。是程序开发者用来编译,调试Java程序的工具包,JDK也是Java程序,需要jre才能运行。为了保持jdk的独立性和完整性,在jdk安装的过程中,jre也是安装的一部分。
jre:(Java Runtime Environment)Java运行环境。所有的Java程序都要在jre上才能运行。
jvm(Java Virtual Machine):Java虚拟机,是jre的一部分,是一个虚拟的机器,通过在真实的机器上仿真模拟各种计算机功能的实现。JVM有自己的一套硬件架构,处理器,堆栈,寄存器等,还有相应的指令系统。其特点是跨平台性。

2. JVM介绍
- JVM的生命周期:
JVM负责运行JAVA程序,当启动JAVA程序时,一个jvm实例也就产生了,当程序关闭退出时,jvm也就随之消亡。

- jvm运行的起点:
jvm实例通过调用某个初始类的main()来运行一个JAVA程序,main()必须是public static void 的,且参数为字符串数组,任何拥有main()的类,都可以作为jvm的起点。

3. JVM的工作过程:

(1)类加载系统(Class Loader System)
Java类的加载由类加载系统完成,它可以加载、连接、初始化类文件。
- 加载:使用类加载器来加载类。类的加载器负责查找并加载类的二进制文件,并在Java堆上创建一个Java.long.Class类的对象。
三种类加载器
Bootstrap ClassLoader():负责加载    J A V A H O M E 中 j r e / l i b / r t . j a r 里 所 有 的 c l a s s , 即 加 载 J a v a 基 础 类 库 中 的 c l a s s 。 E x t e n s i o n   C l a s s L o a d e r ( ) : 负 责 加 载  JAVA_HOME中jre/lib/rt.jar里所有的class,即加载Java基础类库中的class。 Extension ClassLoader():负责加载  JAVAHOMEjre/lib/rt.jarclassJavaclassExtension ClassLoader() JAVA_HOME中jre/lib/*.jar(除rt.jar)或-Djava.ext.dirs指定目录下的jar包,即一些Java平台扩展功能的jar包。
Application ClassLoader():classpath目录下的class文件,即运行当前程序所引入的依赖或者当前程序源代码编译所产生的class。
加载过程(双亲委派模型
当要加载一个类时,先从Application ClassLoader开始,但不自己尝试加载,而是请求委派给父类加载器Extension ClassLoader,Extension ClassLoader也不自己加载,而是委派给Bootstrap ClassLoader。Bootstrap ClassLoader先尝试加载,如果加载失败则Extension ClassLoader加载,如果Extension ClassLoader加载失败则Application ClassLoader加载,如果加载失败则抛出ClassNotFoundException异常。
双亲委派模型的好处:
安全性高:如果黑客自定义的类里面含有病毒,但这个类的class在classpath中,顶多破坏classpath目录下的内容,而不会破坏jvm原有的内容。
保证类的单一性:一个类只能被一个加载器加载一次,以后就存放在这个类加载器加载的目录下,不会出现两个类加载器加载的目录下都有该class文件。
可见性:子类加载器可以看到父类加载器加载得类。
- 连接
连接阶段包括验证、准备、解析三个部分。
验证:验证加载文件的文件格式、元数据、字节码、符号引用;
准备:为加载的类的静态变量分配内存,并将其初始化为默认值;
解析:把类中的符号引用转化为直接引用(所引用的数据实际在内存中的地址)。
- 初始化:为类的静态变量赋予正确的初始值。
- 使用和卸载:等上面类的加载过程(加载-连接-初始化)都完成,就可以使用该类,使用完就可以卸载。

总结:加载–>连接(验证–>准备–>解析)–>初始化–>使用–>卸载

(2)运行时数据区(Runtime Data Area)–>JMM(Java Memory Model)Java内存模型
包括堆、方法区、虚拟机栈、本地方法栈、程序计数器
java内存模型和类的加载机制_第1张图片
- 方法区:存储类信息、静态变量、常量。方法区中有一块区域叫做运行时常量池,存放类的版本、字段、方法和接口等的描述信息。注意,这里只存放描述信息,方法存放在堆的对象中。线程共有。会抛出OutOfMemoryError。
- 堆:存储对象实例和数组。JVM管理的最大的内存区域。垃圾回收机制主要作用于堆。线程共有。在虚拟机启动时创建。会抛出OutOfMemoryError。
- 虚拟机栈:存储局部变量表(八大基本类型+对象的引用+returnAddress(本方法结束后下一部执行的地址))、栈帧数据、操作数栈、动态链接(一些插件的地址信息)。线程私有。生命周期与线程的生命周期同步。会抛出StackOverFlowError(虚拟机栈不允许动态扩容时,当前线程请求的栈深度大于最大深度时会抛出此error,可开启自动扩容机制解决)和OutOfMemoryError(虚拟机栈允许动态扩容,当前线程请求栈深度大于最大深度,无法扩容时会抛出此error,可优化代码来解决)。
- 本地方法栈:存储信息和虚拟机栈类似,只存储native修饰的方法的相关信息。线程私有。生命周期与线程的生命周期同步。也会抛出StackOverFlowError和OutOfMemoryError。
- 程序计数器:下一部要执行的字节码的位置。JMM中唯一不会抛出OutOfMemoryError的内存区域。线程私有。程序计数器的生命周期与线程的生命周期同步。

(3)执行引擎:将运行时数据区的字节码交由执行引擎执行。

4. 类什么时候加载(加载-连接-初始化)
- 创建对象实例,即new对象时,该类还未初始化,就要加载
- 反射时加载:通过class文件来反射创建该类的对象时
- 调用类的静态属性或者给静态属性赋值
- 调用类的静态方法
- 子类初始化时,会先初始化父类
- JVM启动时标记为启动类的类(含main()的类)会被加载

Java类的加载是动态的,并不是一次性将所有的类加载到jvm中,而是按需加载(懒加载),即需要用到那个类时就加载那个类。这样可以节省内存开销。

5. 初始化的顺序:
通过代码实验得知:

class Test{
    public Test(){
        System.out.println("父类成员变量");
    }
}
class TestStatic{
    public TestStatic(){
        System.out.println("父类静态变量");
    }
}
class Test2{
          public Test2(){
              System.out.println("子类成员变量");
          }
}
class Test2Static{
    public Test2Static(){
        System.out.println("子类静态变量");
    }
}
class Father{
    protected  Test a=new Test();
    protected  static TestStatic b=new TestStatic();
    static{
        System.out.println("父类静态块");
    }
    {
        System.out.println("父类实例块");
    }
    public Father(){
        System.out.println("父类构造方法");
    }
}
class Son extends Father{
     private Test2 c=new Test2();
     private static Test2Static d=new Test2Static();
      static{
          System.out.println("子类静态块");
      }
       {
           System.out.println("子类实例块");
       }
       public Son(){
                  System.out.println("子类构造方法");
       }
}
public class TestDemo {
    public static void main(String[] args) {
        Son son=new Son();
    }
}

java内存模型和类的加载机制_第2张图片
大体顺序就是上面的打印结果,值得注意的是:

- 将上面代码的静态块和静态变量顺序改变会改变其执行顺序,意味着静态变量和静态块的初始化顺序是其在代码中的顺序。
- 当给上面代码加入普通方法,但并未调用时,不会初始化。印证了类的加载是懒加载。

你可能感兴趣的:(java内存模型和类的加载机制)