zoukankan      html  css  js  c++  java
  • 面试基础--JVM

    一 类加载

      classs文件是通过类的加载器装载到jvm中的

      java默认的类加载器有三种: 

        1.Bootstrap ClassLoader  启动类加载器:启动类加载器主要加载的是JVM自身需要的类,这个类加载使用C++语言实现的,是虚拟机自身的一部分,

                           它负责将 <JAVA_HOME>/lib路径下的核心类库或-Xbootclasspath参数指定的路径下的jar包加载到内存中,注意必由于虚拟机是按照文件名识别加载jar包的,如rt.jar,

                           如果文件名不被虚拟机识别,即使把jar包丢到lib目录下也是没有作用的(出于安全考虑,Bootstrap启动类加载器只加载包名为java、javax、sun等开头的类)

        2.Extension ClassLoader 扩展类加载器:负责加载java平台中扩展功能的一些jar包,包括$JAVA_HOME中jre/lib/*.jar或-Djava.ext.dirs指定目录下的jar包

        3.App ClassLoader 应用类加载器(系统加载器):负责记载classpath中指定的jar包及目录中class

        

      

    工作过程:

    • 1、当AppClassLoader加载一个class时,它首先不会自己去尝试加载这个类,而是把类加载请求委派给父类加载器Extension ClassLoader去完成。
    • 2、当Extension ClassLoader加载一个class时,它首先也不会自己去尝试加载这个类,而是把类加载请求委派给BootStrapClassLoader去完成。
    • 3、如果BootStrapClassLoader加载失败(例如在$JAVA_HOME/jre/lib里未查找到该class),会使用Extension ClassLoader来尝试加载;
    • 4、若Extension ClassLoader也加载失败,则会使用AppClassLoader来加载
    • 5、如果AppClassLoader也加载失败,则会报出异常ClassNotFoundException

    其实这就是所谓的双亲委派模型。简单来说:如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把请求委托给父加载器去完成,依次向上。

    好处:

    • 防止内存中出现多份同样的字节码(安全性角度)

    特别说明:

    • 类加载器在成功加载某个类之后,会把得到的 java.lang.Class类的实例缓存起来。下次再请求加载该类的时候,类加载器会直接使用缓存的类的实例,而不会尝试再次加载。

    类加载过程

      

    • 加载,查找并加载类的二进制数据,在Java堆中也创建一个java.lang.Class类的对象。
    • 连接,连接又包含三块内容:验证、准备、初始化。
    • 验证,文件格式、元数据、字节码、符号引用验证;
    • 准备,为类的静态变量分配内存,并将其初始化为默认值;
    • 解析,把类中的符号引用转换为直接引用
    • 初始化,为类的静态变量赋予正确的初始值。

      

    二 JVM内存模型

    • 堆:存放对象实例,几乎所有的对象实例都在这里分配内存
    • 虚拟机栈:虚拟机栈描述的是Java方法执行的内存模型:每个方法被执行的时候都会同时创建一个栈帧(Stack Frame)用于存储局部变量表、操作栈、动态链接、方法出口等信息
    • 本地方法栈:本地方法栈则是为虚拟机使用到的Native方法服务。
    • 方法区:存储已被虚拟机加载的类元数据信息(元空间)
    • 程序计数器:当前线程所执行的字节码的行号指示器

    举例说明:

    public class Java3yTest {
     
        public static void main(String[] args) {
    
            Java3y java3y = new Java3y();
     
            java3y.setName("Java3y");
     
            System.out.println(java3y);
        }
     
    }

    • 1、通过java.exe运行Java3yTest.class,随后被加载到JVM中,元空间存储着类的信息(包括类的名称、方法信息、字段信息..)。
    • 2、然后JVM找到Java3yTest的主函数入口(main),为main函数创建栈帧,开始执行main函数
    • 3、main函数的第一条命令是Java3y java3y = new Java3y();就是让JVM创建一个Java3y对象,但是这时候方法区中没有Java3y类的信息,所以JVM马上加载Java3y类,把Java3y类的类型信息放到方法区中(元空间)
    • 4、加载完Java3y类之后,Java虚拟机做的第一件事情就是在堆区中为一个新的Java3y实例分配内存, 然后调用构造函数初始化Java3y实例,这个Java3y实例持有着指向方法区的Java3y类的类型信息(其中包含有方法表,java动态绑定的底层实现)的引用
    • 5、当使用java3y.setName("Java3y");的时候,JVM根据java3y引用找到Java3y对象,然后根据Java3y对象持有的引用定位到方法区中Java3y类的类型信息的方法表,获得setName()函数的字节码的地址
    • 6、为setName()函数创建栈帧,开始运行setName()函数
  • 相关阅读:
    控制翻转与容器
    构造函数传递参数
    bean属性检查
    tomcat源码阅读14
    Block Formatting Context
    IE 兼容性问题的处理
    JavaScript 的原型与继承
    IE 多版本测试工具 IETester
    callee,caller,call,apply
    HDOJ2175 汉诺塔IX
  • 原文地址:https://www.cnblogs.com/lensener/p/10454947.html
Copyright © 2011-2022 走看看