我爱学习,这一更大概路会和上一更在同一时间更新。所以就先期待一下!
正文分割线
一、类的加载机制:
1、类的加载机制总览:首先上一张整图
我们都知道Java程序的实现是通过Java代码-字节码-编译程序。我们主要讲解的还是class后缀文件加载到jvm虚拟机中的操作。具体的加载步骤如下图,我们也将按顺序讲解下图中的步骤。
2、类加载的步骤:
1)、第一步加载:将class文件中的内容,使用io流读取到jvm所在的内存。加载时,需要使用3个类加载器,他们分别是根类加载器,扩展类加载器,系统类加载器。他们之间存在父子关系。扩展类加载器的父类是根类加载器,子类是系统类加载器。
根类加载器:主要是加载Java的核心代码;java.*
扩展类加载器:加载Java的扩展代码,类似于Javax.*
系统类加载器:加载我们所写的代码。
类加载的具体流程:
1、Java.exe程序搜索jre目录,寻找jvm,并启动jvm。
2、jvm运行根类加载器,该根类加载器加载Java核心api。
3、根类加载器运行后,它会自动加载扩展类加载器和系统加载器,并将扩展类加载器的父类设置为根类加载器,将应用加载器的父亲设置为扩展类加载器。
4、扩张类加载器加载搜索JAVA_HOME/jre/lib/ext目录,并加载扩展api。
5、应用加载器搜索classpath目录,加载我们要运行的类。
6、类的class文件读入内存后,就会创建一个Java.lang.Class对象。也就是说,当Java程序中使用任何类时,系统都会为之创建一个Java.lang.Class对象。一旦某个类被载入jvm中,同一个类就不会再次被载入。
注意:一旦某个类被载入jvm中,同一个类就不会再次被载入。
类的加载机制-双亲委派
为什么要进行双亲委派呢?主要是为了防止程序员修改系统代码
2)、第二步连接:当类被加载后,系统就为之创建一个对应的class对象,接着就会进入连接阶段。连接阶段会负责把类的二进制数据合并到jre中。连接如下图所示也分为3个步骤。
验证:判断class中的内容,能否运行在当前jvm版本上,你不要做jdk1.8的代码,放在jdk1.7去运行。
准备:给static修饰的类变量赋初值,基本数据类型赋值为0,引用数据类型赋值为null。
解析:将类的二进制数据中的符号引用替换成直接引用。
3)、第三步初始化:
类初始化,第一个事情,就是针对静态变量赋初值,例如pi=3.14。
第二个事情,执行类中static修饰的静态初始化代码块代码。
初始化的步骤:
1)假如这个类还没有被加载和连接,程序先加载并连接该类。
2)假如该类的直接父类还没有被初始化,则先初始化其直接父类。
3)假如该类中有初始化语句,则系统依次执行这些初始化语句。
3、类的初始化的6种情况
1、创建类的实例子。
2、调用某个类的静态方法。
3、访问某个类或者接口的静态属性,或者为静态属性赋值。
4、使用反射方式强制创建某个类或接口对应的java.lang.Class对象。
5、初始化某个类的子类。
6、直接使用java.exe命令运行某个主类。
二、GC垃圾回收
1、总览:GC垃圾回收就是系统监视每一个类对象,如果该类没有被引用,就把该类销毁释放内存空间。
2、堆的空间分配:我们之前知道类一般是存放在堆中,所以垃圾回收的主战场还是在堆中。
堆空间中有新生代,老年代,持久代。后来我们把持久代单独归为元空间分割出来。而新生代中又分为Eden和Survive,Survive又分为from和to。
eden、from和to的内存比例为8:1:1
新生代和老年代的内存比例为1:2
3、垃圾回收的算法:
标记算法:标记对象的引用次数 当次数>0 表示对象正在被使用,当==0时,表示对象可以被清理。
清理算法:就是将对象从内存中干掉,一般来讲清理之后,会有内存的碎片,需要整理。
复制算法:就是将对象在转移时,copy复制一份,同样要记录复制次数。
4、回收的步骤:
第一次回收:当eden空间满了,gc线程将会检查每个对象的使用次数标记,当标记为0时,表示该对象已经没有被引用,可以被gc回收。当前标记不为0的,表示该对象依旧有引用,将使用复制算法将对象复制到form区间,并记录它的复制次数为1.
第二次回收:当eden空间再次满了,gc线程同事检查eden和from区间,判断每个对象的使用次数标记。为0则被回收,不为0使用复制算法将对象复制到to区间,并记录它的复制次数为2,将to改名为from.
第三次回收:当eden空间再次满了,gc线程同事检查eden和from区间,判断每个对象的使用次数标记。为0则被回收,不为0使用复制算法将对象复制到to区间,并记录它的复制次数为2,from改名为to,将to改名为from。
第N次:一直重复,不过当一个对象的复制次数>15次,依旧再次引用。此时对象将被复制到老年代,老年代如果满了,就会触发:full gc(全量垃圾回收)
5、如何优化JVM
总体思想:尽量的减少 Full GC()的次数,方法:调整新生代 和老年代的内存比例,调整新生代中Eden 和 Survive的内存比例,以及尽量不要存在那种长时间持有对象引用的类
6、Java的优势
Java语言牛逼就牛逼在,我们不需要进行垃圾回收,其他的都需要。因为JVM有一个称为垃圾回收器的低级线程,这个线程在后台不断地运行,自动寻找在Java程序中不再被使用的对象,并释放这些对象的内存。这种内存回收的过程被称为垃圾回收(Garbage Collection)。通过调用对象身上的finalize()方法,进行销毁对象。
代码举例
//试图重写String的方法
package java.lang;
public class String {
public int length() {
return 0;
}
}
package com.woniuxy.java23.loader;
public class MainEnter {
public static void main(String[] args) {
TeacherBean teacher = new TeacherBean();
//返回加载TeacherBean的加载类
System.out.println(teacher.getClass().getClassLoader());
//返回系统类加载器的父类
System.out.println(teacher.getClass().getClassLoader().getParent());
//返回扩展类加载器的父类
System.out.println(teacher.getClass().getClassLoader().getParent().getParent());
//防止 我们乱改它的核心代码,或者扩展代码
String str = "1231231";
System.out.println(str.length());
}
}
代码的执行结果:length() == 7 不是0