目录
- JVM理解
- JVM生命周期
- JVM架构图
- 类的加器分类
- 1:字节码篇
- 1.0:字节码工具
- 2:类的加载篇
- 2.0:api
- 2.1:启动类加载器(Bootstrap ClassLoader)
- 2.2:扩展类加载器(Extension ClassLoader)
- 2.3:系统类加载器(AppClassLoader)
- 2.4:自定义类加载器
- 3:运行时内存篇
- 3.0:堆内存大小参数
- 3.1:内存溢出dump文件分析
- 4:垃圾回收篇
- 4.1:垃圾判别算法
- 5:JVM监控及诊断工具篇
- 5.0: 命令行篇
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.jarfile:/D:/ProgramFiles/Java/jdk1.8.0_251/jre/lib/rt.jarfile:/D:/ProgramFiles/Java/jdk1.8.0_251/jre/lib/sunrsasign.jarfile:/D:/ProgramFiles/Java/jdk1.8.0_251/jre/lib/jsse.jarfile:/D:/ProgramFiles/Java/jdk1.8.0_251/jre/lib/jce.jarfile:/D:/ProgramFiles/Java/jdk1.8.0_251/jre/lib/charsets.jarfile:/D:/ProgramFiles/Java/jdk1.8.0_251/jre/lib/jfr.jarfile:/D:/ProgramFiles/Java/jdk1.8.0_251/jre/classesnull
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:ProgramFilesJavajdk1.8.0_251jrelibextC:WINDOWSSunJavalibextsun.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; } @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