jvm简介:
JVM 是可运行 Java 代码的假想计算机 ,包括一套字节码指令集、一组寄存器、一个栈、一个垃圾回收,堆 和 一个存储方法域。JVM 是运行在操作系统之上的,它与硬件没有直接
的交互。
1.java为什么能跨平台平台运行?
java运行过程:
① Java 源文件—->编译器—->字节码文件
② 字节码文件—->JVM(解释器)—->机器码
①过程产生的字节码文件不可以直接运行,java是运行在 JVM上的,在不同的平台对应相应的JVM来解释字节码文件变成机器码运行.
2.垃圾回收机制:
java堆从GC上分可分为新生代(Eden 区、From Survivor 区和 To Survivor 区)和老年
代.
新生代:
Eden 区:占堆的三分之一,java新对象存入其中,(如果新创建的对象占用内存很大则存入老年代)Eden区内存不够时MinorGC来进行垃圾回收
SurvivorFrom区:
上一次GC的幸存者,这一次GC的被扫描者
SurvivorTo区:
保存一次GC的幸存者
MinorGC:采用复制算法(复制->清空->互换)
1.复制过程:
Eden区 和SurvivorFrom中存活的对象复制到SurvivorTO区(同时年纪+1如果年纪符合要求就送到老年区)如果SurvivorTO区内存不够送到老年区
2.清空过程:
将Eden区和SurvivorFrom区的对象清空
3.互换过程:
最后,ServicorTo 和 ServicorFrom 互换,原 ServicorTo 成为下一次 GC 时的 ServicorFrom
区.
类加载机制:
类的一生有7个步骤:
加载->链接(验证-》准备-》解析)->初始化->使用->卸载
类的加载过程有五步:
加载->链接(验证-》准备-》解析)->初始化,(验证-》准备-》解析)这三部可以统称为链接
在加载阶段,虚拟机需要完成以下三件事情:
(1). 通过一个类的全限定名来获取定义此类的二进制字节流(并没有指明要从一个Class文件中获取,可以从其他渠道,譬如:网络、动态生成、数据库等);
(2). 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构;
(3). 在内存中(对于HotSpot虚拟就而言就是方法区)生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口;
在验证阶段:
对Class文件的二进制流包含的信息进行验证其是否符合jvm规范和是否会危害到jvm的安全;
这个过程很重要,但并不是必须的;
在准备阶段:
给类的静态成员分配内存(在方法区中),并为它们赋默认值,如果变量使用final修饰在此过程就是赋予用户定义的值如:static final a=100;
此时a就是100,如果没用final修饰此时a为0;
解析阶段:
将常量池内的符号引用替换为直接引用的过程。解析动作主要针对类或接口、字段、类方法、接口方法、方法类型、方法句柄和调用点限定符7类符号引用进行。
初始化过程:
为类的静态成员赋值,赋值语句是重static{}静态块和对类变量赋值的语句合并产生的
类初始化的时机:
类只有首次主动被调用才会触发初始化过程,有以下几种情况
1.主动创建对象;
2.子类初始化,父类会先初始化;
3.使用反射加载类的对象
4.获取类的静态成员和为静态成员赋值(用final修饰的不算),静态方法的调用;
5.虚拟机启动时被标明为启动类的类(就是main方法存在的那个类)最先初始化
类加载器及双亲委托机制:
类加载器的种类:
1.Bootstrap ClassLoader:
根类加载器,它负责加载Java的核心类%JAVA_HOME%lib(如rt.jar)。根类加载器不是java.lang.ClassLoader的子类(其他类加载器都是它的子类),而是由JVM自身实现的。
2.Extension ClassLoader:
扩展类加载器,主要加载%JAVA_HOME%lib/ext目录下的类,java.ext.dir指定位置中的类库;
3.System ClassLoader:
应用程序类加载器,主要加载CLASSPATH下的类,没有自定义类加载器一般默认为系统类加载器
4.用户自定义类加载器
没有自定义类加载器默认使用系统加载器;
双亲委派机制:
类加载器和类的一些关系介绍:
类是通过类名和类加载器来确定类在JVM中的唯一标识,类加载器通过类的全限定名加载类,会产生一个类命名空间,被同一个类加载器加载的类都存在于这一空间内,彼此可见,,不同类加载器加载的类彼此不可见;
双亲委派机制的介绍:
双亲委派机制是指当一个类加载器去加载类的时候它先会请求它的父加载器去加载这个类,如果父加载器加载不了这个类,它就自己加载,否则父加载器加载该类;类加载器之间的关系如下:
所以为什么会出现双亲委派机制呢?
上面其实已经给出了答案,相同类加载器加载的类是相互可见的,不同类加载器加载的类相互是不可见的,这样就出现了一个问题,Object类是所有类的父类,如果没有双亲委托,用户自己编写了Object类就会由系统类加载器去加载它,这个时候就存在两个不同的Object类,这样Object类就失去了它的作用,因为双亲委派机制Object 类会被启动类加载器加载所以用户自定义的Object 类不会生效;
双亲委派机制的坏处:
对于SPI(服务提供者接口)比如JDBC是一种规范,而它的具体实现是由对应厂家提供(如Mysql,Oracle厂家提供的一些jar包),如果按照双亲委派机制,JDBC因该由跟加载加载,而对应厂家提供的jar包则是由系统类加载器来加载的,所以它们彼此不可见,这样就不友好,这个时候就要推出一个新的概念来完成这个需求那就是破坏双亲委派机制;
线程上下文加载器破坏双亲委派机制
线程上下文加载器的使用步骤;
1.获取线程上下文加载器,默认为系统类加载器;
ClassLoader cl = Thread.currentThread().getContextClassLoader();
2.将线程上下文加载器传入到对应的方法中,执行相应的操作;