目录
JVM理解
JVM生命周期
JVM架构图
类的加器分类
1:字节码篇
1.0:字节码工具
1:官方查看字节码工具: javap
2:IDEA查看字节码工具
- IDEA下载jclasslib插件,编译java文件
- 点击View, 找到 Show Bytecode With Jclasslib
2:类的加载篇
2.0:api
方法 | 描述 |
---|---|
getClassLoader() | 获取加载器 |
getParent() | 获取父类加载器 |
@Test
public void test1(){
// 对于自定义类,使用系统类加载器进行加载
ClassLoader classLoader = ClassLoaderTest.class.getClassLoader();
System.out.println(classLoader);
//调用系统类加载器的getParent();获取扩展类加载器
ClassLoader classLoader1 = classLoader.getParent();
System.out.println(classLoader1);
//调用扩展加载器的getParent():无法获取引导类加载器
// 引导类加载器主要负责加载java的核心类库,无法加载自定义类的。
ClassLoader classLoader2 = classLoader1.getParent();
System.out.println(classLoader2);
//String的加载类是类加载器。
ClassLoader classLoader3 = String.class.getClassLoader();
System.out.println(classLoader3);
}
2.1:启动类加载器(Bootstrap ClassLoader)
package chapter04.java;
import java.net.URL;
/**
* 加载器测试
*/
public class ClassLoaderTest {
public static void main(String[] args) {
System.out.println("**********启动类加载器**************");
// 获取 BootstrapClassLoader 能够加载的 api 的路径
URL[] urLs = sun.misc.Launcher.getBootstrapClassPath().getURLs();
for (URL element : urLs) {
System.out.println(element.toExternalForm());
}
// 从上面的路径中随意选择一个类,来看看他的类加载器是什么:引导类加载器
ClassLoader classLoader = java.security.Provider.class.getClassLoader();
System.out.println(classLoader);// null 引导类加载器是获取不到的
}
}
执行结果
**********启动类加载器**************
file:/D:/ProgramFiles/Java/jdk1.8.0_251/jre/lib/resources.jar
file:/D:/ProgramFiles/Java/jdk1.8.0_251/jre/lib/rt.jar
file:/D:/ProgramFiles/Java/jdk1.8.0_251/jre/lib/sunrsasign.jar
file:/D:/ProgramFiles/Java/jdk1.8.0_251/jre/lib/jsse.jar
file:/D:/ProgramFiles/Java/jdk1.8.0_251/jre/lib/jce.jar
file:/D:/ProgramFiles/Java/jdk1.8.0_251/jre/lib/charsets.jar
file:/D:/ProgramFiles/Java/jdk1.8.0_251/jre/lib/jfr.jar
file:/D:/ProgramFiles/Java/jdk1.8.0_251/jre/classes
null
2.2:扩展类加载器(Extension ClassLoader)
package chapter04.java;
import java.net.URL;
/**
* 加载器测试
*/
public class ClassLoaderTest {
public static void main(String[] args) {
System.out.println("***********扩展类加载器加载路径*************");
String extDirs = System.getProperty("java.ext.dirs");
for (String path : extDirs.split(";")) {
System.out.println(path);
}
// 从上面的路径中随意选择一个类,来看看他的类加载器是什么:扩展类加载器
ClassLoader classLoader1 = sun.security.ec.CurveDB.class.getClassLoader();
System.out.println(classLoader1); // sun.misc.Launcher$ExtClassLoader@1540e19d
}
}
执行结果
***********扩展类加载器加载路径*************
D:\ProgramFiles\Java\jdk1.8.0_251\jre\lib\ext
C:\WINDOWS\Sun\Java\lib\ext
sun.misc.Launcher$ExtClassLoader@5cad8086
2.3:系统类加载器(AppClassLoader)
通过ClassLoader的getSystemClassLoader() 方法可以获取到该类加载器
2.4:自定义类加载器
- 继承ClassLoader类
- 重写findclass()方法;
public class MyClassLoader extends ClassLoader {
private String path;
public MyClassLoader(String path) {
this.path = path;
}
public MyClassLoader(String path, ClassLoader parentClassLoader) {
super(parentClassLoader);
this.path = path;
}
/**
* 重写父类的findClass方法,在ClassLoader在执行 loadClass 方法时,
* 如果父加载器不会加载类,就会调用当前重写的方法进行加载类
*/
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
BufferedInputStream bis = null;
ByteArrayOutputStream baos = null;
try {
bis = new BufferedInputStream(new FileInputStream(path + name + ".class"));
baos = new ByteArrayOutputStream();
int len;
byte[] data = new byte[1024];
while ((len = bis.read(data)) != -1) {
baos.write(data, 0, len);
}
//获取内存中的完整的字节数组的数据
byte[] classByteArray = baos.toByteArray();
//将字节数组转换为Class的实例
return defineClass(null, classByteArray, 0, classByteArray.length);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (null != baos) {
baos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if (null != bis) {
bis.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
}
测试:
public class MyClassLoaderTest {
public static void main(String[] args) throws ClassNotFoundException {
MyClassLoader myClassLoader = new MyClassLoader("d:/");
Class<?> aClass = myClassLoader.loadClass("Demo");
System.out.println("加载此类的类加载器为: " + aClass.getClassLoader());
System.out.println("加载此类的类加载器的父类加载器为: " + aClass.getClassLoader().getParent().getClass().getName());
}
}
运行结果:
加载此类的类加载器为: com.wsh.MyClassLoader@2f2c9b19
加载此类的类加载器的父类加载器为: sun.misc.Launcher$AppClassLoader
3:运行时内存篇
3.0:堆内存大小参数
- -Xms:初始堆大小
- -Xmx:最大堆大小
- -XX:NewRatio:设置新生代和老年代的比值。如:为3,表示年轻代与老年代比值为1:3
- -XX:PrintGCDetails:查看程序运行GC的运行情况
3.1:内存溢出dump文件分析
4:垃圾回收篇
4.1:垃圾判别算法
- 引用技术算法:
给对象添加一个引用计数器,每当对象被引用了,计数器加1,当引用失效之后,计数器减1,当值为0时就是可回收的对象。该方法存在一个循环引用的问题,如下代码
public class Test{
public static void mian(String[] args){
ObjectA A=new ObjectA();
ObjectB B=new ObjectB();
A=B;
B=A;
A=null;
B=null;
}
}
在这段代码中,代码执行到B=A该语句时,ObjectA和ObjectB的引用计数均为2,而执行代码结束之后,A和B都置为null,两个对象的计数均减1,但是还存在着A和B之间的相互引用,此时ObjectA和ObjectB的引用计数仍为1,而A和B两个实例又早已不用,终将会进入一种循环状态,导致无法被当成垃圾进行回收。 |
---|
- 可达性分析算法
判断对象与GCRoot是否有引用链,即是否可达,如果对象到GCRoot没有任何引用链,则对象是不可用的,可被当成垃圾进行回收;如果是可达的,则对象不可回收。
如A与GCRoot有相连,B与A相连,C与B相连,这几个对象都是与GCRoot有连接,都是可达对象
而出现一个D不与上述某一对象连接,或者是链接了一个不与GCRoot有连接的对象,则它与GCRoot不可达,是可回收的对象
5:JVM监控及诊断工具篇
5.0: 命令行篇
- jps:查看正在运行的java进程
- jmap:dump内存文件
例如:jmap -dump:live,format=b,file=zhang.hprof pid