先介绍一下类加载的过程:
我们编写的是源码文件java,通过jdk bin下面的javac工具,编译为class字节码文件,然后通过bin下面的java命令调用jvm解析class文件运行。
java实际运行的时候依靠的是字节码,之所以说java跨平台就是因为jvm能够跨平台,只要有jvm的地方,java都可以运行。
JVM装在Class文件的过程: 装载,准备,解析。
JVM通过类加载器完成类的装载过程,具体如图所示
1.先通过 启动类加载器,完成基础类的加载 lib下面的 rt.jar(c++编写)
2.通过拓展类加载器,完成拓展类的加载 lib下面的 ext目录下的拓展类(java编写)
3.最后才是通过应用程序加载器完成我们自己的类加载过程。
注意:该类加载器通过双亲委托机制完成。(简单说:一个类的加载显示在应用类加载器,找到上一级拓展类加载器,再继续网上找启动类加载器,如果顶级有权利加载,则进行加载,如果找不到才会往下一级继续,这样做的好处就是,防止其他人编写系统预置的核心类,保证运行安全,比如如果我们编写了相同的类String,如果不采用双亲委托机制,会破坏内置的String类加载。)
举例:
package com;
public class LoaderDemo {
/**
* @param args
*/
public static void main(String[] args) {
System.out.println(LoaderDemo.class.getClassLoader().getClass()
.getName());
System.out.println(LoaderDemo.class.getClassLoader().getParent()
.getClass().getName());
System.out.println(LoaderDemo.class.getClassLoader().getParent()
.getParent().getClass().getName());
}
}
我通过代码获取当前类加载器和他们的上级类加载器;
我们清晰的可以看见,当前类加载器是appclassloader,父类加载器是ext,顶级因为是bootclassloader,c++编写的 我们获取不到,故抛出异常。
------------------------------------------------------------------------------------------------------
上面是类记载的过程,那么我们的内存是如何区别的呢?
JAVA内存模式模型:
Java内存主要其实是堆和非堆,细分可以分成如图的5部分。当我们的JVM把class字节码通过classloader载入内存后
JAVA stack 栈:基本数据类型和对象的引用地址。
heap 堆:实例化的对象(new)和数组对象。method area方法区:元数据信息,常量等。
native method stack && program counter register:线程创建或者方法生成的时候生成的栈帧。
堆:细分为 新生代,老生代和持久代。
新生代:存放新生的对象。
老生代:新生代中长期没有被回收的对象,也就是说生命周期比较长的对象。
持久代:生命周期最长的区域,几乎不会被GC回收。(存放class和meta的信息。)
所谓的垃圾回收机制:其实回收的是堆空间里面的对象,jvm通过有向图的方式来确定对象是否具备回收的条件。当一个对象没有被任何对象所引用的时候,jvm的gc就准备回收。回收的时候,优先回收jvm新生代里面的对象,然户是老生代,持久代基本不回收。
GC算法:分代处理。过程如上
FullGC和GC区别:
GC:一般只回收新生代区域对象。
FullGC:回收新生代和老生代的区域。System.gc 其实是FullGC,应该少调用,尽量不去使用,由JVM来完成最好。即便System.gc 也未必马上回收,JVM内部有特性算特性算法完成。