idea安裝好熱加載插件 JRebel,啟動后報錯java.lang.OutOfMemoryError: PermGen space解決方法
報錯原因是因為內存溢出了,也就是內存不足,方法就是增加內存,添加如下配置:

參數解釋:
-Xms,表示程序啟動時,JVM 堆的初始化最小尺寸參數;
-Xmx,表示程序啟動時,JVM 堆的初始化最大尺寸參數;
-XX:PermSize,表示程序啟動時,JVM 方法區的初始化最小尺寸參數;
-XX:MaxPermSize,表示程序啟動時,JVM 方法區的初始化最大尺寸參數。
激活JRebel
生成 GUID 的網址:https://www.guidgen.com/
用這個網址 + 生成的 GUID 激活
https://jrebel.qekang.com/
例如:
https://jrebel.qekang.com/cb2546bb-9d43-4115-bf4b-10539349efed
設置離線模式 來防止失效
File -> Settings -> JRebel -> [Work offline]按鈕
既然用了這個熱加載,就了解一下這個熱加載原理
一、java類加載
java的類加載過程
一個java類文件到虛擬機里的對象,要經過如下過程:

首先我們編寫好了的java源代碼通過java編譯器,將java源代碼文件編譯成class字節碼,類加載器讀取class字節碼,再將類轉化為實例,對實例newInstance就可以生成對象。
類加載器ClassLoader功能,也就是將class字節碼轉換為類的實例。在java應用中,所有的實例都是由類加載器,加載而來。一般在系統中,類的加載都是由系統自帶的類加載器完成,而且對於同一個全限定名的java類(如com.csiar.soc.HelloWorld),只能被加載一次,而且無法被卸載。
加載class字節碼的工作是由類加載器實例去實現的,類加載器支持通過文件目錄,jar,zip,網絡等多種途徑,加載class字節碼文件。
JVM啟動后就默認有三個類加載器實例,負責去加載不同位置的class。
1.核心類庫加載器 BootStrap ClassLoader,負責加載jdk安裝目錄下lib文件夾里面的jar包,我們的String.class,System.class這些類都放在這個目錄下面,啟動jvm就會去加載,必不可少。
2.拓展類庫加載器 Extension ClassLoader,負責加載jdk安裝目錄下lib/ext文件夾里面的jar包,這里面是一些jdk的拓展jar包,比如zipfs.jar這樣的包或工具類。拓展的意思就是在某些情況下,這些jar包不加載也不影響jvm工作。
3.應用程序代碼加載器 Application ClassLoader,負責加載我們自己寫的程序代碼,通過java命令 -cp 或者 -classpath告訴jvm我們的代碼class存放位置。如果我們的程序是jar包運行,你可以在jar包 META-INF目錄MANIFEST.MF文件里面看到一個Class-Path: .配置,這就是指定代碼位置的。
java類加載的階段

加載階段
找到類的靜態存儲結構,並加載到虛擬機里面,然后轉換成方法區的運行時數據結構,生成class對象,加載階段,用戶可以自定義類加載器參與進來。
驗證階段
主要確保字節碼安全的,確保不會對虛擬機安全造成危害,可以通過JVM啟動參數來禁用一些驗證,但不推薦修改設置,參數禁用可能會對虛擬機安全造成一些危害。
准備階段
確定內存布局,初始化內存變量,注意點:賦初始值,不會執行程序自己定義的賦值操作,比如定義了一個私有變量:private static int count = 12,在准備階段並不是把count初始為了12,這里是會賦初始值,int初始值為0,所以會把這私有靜態變量賦值為0,而不是12。
解析階段
這個階段主要是將符號引用變為直接引用。
初始化階段
調用程序自定義的代碼。比如private static int count = 12, count在本階段將會被初始化為12,而不是之前准備階段的0,初始化階段會生成clean int 方法,這個方法由編譯器自動收集類中的所有類變量的賦值、動作和靜態語句塊中的語句合並,同一個類加載器中,只會將一個類型初始化一次。
Java虛擬機沒有強制約束什么時候開始初始化階段,但規定了5種情況必須立即初始化,當然這之前的幾種操作都是已經運行了的。5種情況如下:
1.遇到new、 get static 、post static、 invoke static這四條字節碼指令的時候,如果類沒有初始化,需要觸發初始化,注意的是final修飾的類,會在編譯期的時候,將結果放在常量池,即使調用也不會觸發初始化,因為final修飾的是常量,會把常量放在常量池,調用常量不會觸發初始化這個階段。
2.使用java.long.reflect包里方法,即對類進行反射調用的時候,如果類沒初始化的話,需要初始化。
3.當初始化一個子類的時候,如果父類還沒有初始化,需要先初始化父類,再初始化子類。
4.虛擬機啟動的時候,用戶制定一個要執行的主類,虛擬機會先初始化這個主類,例子:我們寫的java程序,在某一個類里面寫了一個main方法,通過運行這個main方法啟動這個程序,虛擬機會先初始化這個main方法所在的類。
5.使用jdk1.7動態語言支持的時候,如果java.lang.invoke.methondhandler類實例解析的最后結果是ref_getstatic、ref_putstatic、ref_invokestatic方法句柄的時候,如果句柄對應的類沒有初始化,那就需要先初始化句柄對應的類。
二、Java類加載器的特點
1.由AppClass Loader(系統類加載器)開始加載指定的類;
2.類加載器將加載任務交給其父類,如果其父類找不到,再交給自己去加載(即雙親委派);
3.Bootstrap Loader (啟動類加載器)是最頂級的類加載器。
三、熱加載原理
熱加載的實現原理主要依賴java的類加載機制,在實現方式可以概括為在容器啟動的時候起一個后台線程,定時的檢測類文件的時間戳變化,如果類的時間戳變化了,則將類重新載入。
對比反射機制,反射是在運行時獲取類信息,通過動態的調用來改變程序行為; 熱加載則是在運行時通過重新加載改變類信息,直接改變程序行為。
四、參考博文
(1) https://www.cnblogs.com/cdcr/p/9737166.html (熱加載插件啟動時報內存溢出解決方法)
(2) https://blog.csdn.net/wing_93/article/details/78561736 (熱部署原理解析以及熱部署實現)
(3) https://blog.csdn.net/u013159507/article/details/82960847 (類加載過程)
