1.1 編譯CLPreparation.java文件並且反編譯生成字節碼
CLPreparation的源碼:
package com.iqiyi.jvm.serializable;
/**
* Created by leixingbang on 2019/8/1.
*/
public class CLPreparation {
public static int a = 111111;//靜態變量
public static final int INT_CONSTANT = 22222;//原始類型常量
public static final Integer INTEGER_CONSTANT = Integer.valueOf(3333333);//引用類型
}
編譯並使用javap -v 命令反編譯.class文件生成字節碼
[root@audit-video-history-1f6396079-1 ~]# javac CLPreparation.java
[root@audit-video-history-1f6396079-1 ~]# ll
total 24
-rw-r--r-- 1 root root 509 Aug 2 12:12 CLPreparation.class
-rw-r--r-- 1 root root 286 Aug 1 19:37 CLPreparation.java
[root@audit-video-history-1f6396079-1 ~]# javap -v CLPreparation.class
Classfile /root/CLPreparation.class
抓取字節碼的源關鍵部分源文件,從源文件中可以看出靜態變量值的真正初始化(對a進行11111賦值),需要調用putstatic的jvm指令,而使用該指令是在顯示初始化時候執行的。加載—驗證–準備—解析–初始化–卸載
static {};
descriptor: ()V
flags: ACC_STATIC
Code:
stack=1, locals=0, args_size=0
0: ldc #2 // int 111111
2: putstatic #3 // Field a:I
5: ldc #4 // int 3333333
7: invokestatic #5 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
10: putstatic #6 // Field INTEGER_CONSTANT:Ljava/lang/Integer;
13: return
LineNumberTable:
line 7: 0
1.2雙親委託模型
作用是避免重複加載,造成浪費。
1.3類加載機制的三個特性
- 雙親委派模型
- 可見性 子類加載器可以看到父類加載器的類型,反過來不可以。
- 單一性 父加載器的類型對子類可見,所以父加載器加載過類型子類不會重複加載。
1.4 自定義類的加載過程
-
步驟(1)通過定義的名稱'com.iqiyi.leetcode.CheckBracketsTest'找到對應二進制的實現‘CheckBracketsTest.class’,這裏就可以截取,修改字節碼 步驟(2)調用父類的define class 方法,完成類的加載過程。
自定義實現Classloader類:
/** * 文件加載類 * 可根據MyFileClassLoader 從文件中動態生成類 * * @author chengmingwei */ public class MyFileClassLoader extends ClassLoader { private String classPath; public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { MyFileClassLoader fileClsLoader = new MyFileClassLoader(); fileClsLoader.setClassPath("D:\\myPoject\\leetcode\\target\\test-classes\\"); Class cls = fileClsLoader.loadClass("com.iqiyi.leetcode.CheckBracketsTest"); Object obj = cls.newInstance(); Method[] mthds = cls.getMethods(); for (Method mthd : mthds) { String methodName = mthd.getName(); System.out.println("mthd.name=" + methodName); } System.out.println("obj.class=" + obj.getClass().getName()); System.out.println("obj.class=" + cls.getClassLoader().toString()); System.out.println("obj.class=" + cls.getClassLoader().getParent().toString()); } /** * 根據類名字符串從指定的目錄查找類,並返回類對象 */ @Override protected Class<?> findClass(String name) throws ClassNotFoundException { byte[] classData = null; try { //步驟(1)通過定義的名稱'com.iqiyi.leetcode.CheckBracketsTest'找到對應二進制的實現‘CheckBracketsTest.class’,這裏就可以截取,修改字節碼 classData = loadClassData(name); } catch (IOException e) { e.printStackTrace(); } //步驟(2)調用父類的define class 方法,完成類的加載過程。 return super.defineClass(name, classData, 0, classData.length);// } /** * 根據類名字符串加載類 byte 數據流 * * @param name 類名字符串 例如: com.cmw.entity.SysEntity * @return 返回類文件 byte 流數據 * @throws IOException */ private byte[] loadClassData(String name) throws IOException { File file = getFile(name); FileInputStream fis = new FileInputStream(file); byte[] arrData = new byte[(int) file.length()];//一次性讀取文件到二進制數組 fis.read(arrData); return arrData; } /** * 根據類名字符串返回一個 File 對象 * * @param name 類名字符串 * @return File 對象 * @throws FileNotFoundException */ private File getFile(String name) throws FileNotFoundException {//獲取文件 File dir = new File(classPath); if (!dir.exists()) throw new FileNotFoundException(classPath + " 目錄不存在!"); String _classPath = classPath.replaceAll("[\\\\]", "/"); int offset = _classPath.lastIndexOf("/"); name = name.replaceAll("[.]", "/"); if (offset != -1 && offset < _classPath.length() - 1) { _classPath += "/"; } _classPath += name + ".class"; dir = new File(_classPath); if (!dir.exists()) throw new FileNotFoundException(dir + " 不存在!"); return dir; } public String getClassPath() { return classPath; } public void setClassPath(String classPath) { this.classPath = classPath; } }
1.5 從類的加載角度優化java啓動(啓動爲重點)速度。
字節碼(.class文件)與平臺無關,但是二進制文件加載 需要加載–驗證–解析–初始化 這些步驟會導致java的啓動速度變慢。
提速的方式:
- AOT 。編譯時直接編譯爲機器碼,降低解析的開銷。
- AppCDS.將通過內存映射直接映射到內存的地址空間,而不是走加載延、驗證解析等步驟。
1.6 java hell 包衝突
同一個類在不同的jar包中有不同的版本。