您好,登錄后才能下訂單哦!
這篇文章主要介紹“JVM內存增強之逃逸分析怎么使用”,在日常操作中,相信很多人在JVM內存增強之逃逸分析怎么使用問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”JVM內存增強之逃逸分析怎么使用”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!
逃逸分析一種數據分析算法,基于此算法可以有效減少 Java 對象在堆內存中的分配。 Hotspot 虛擬機的編譯器能夠分析出一個新對象的引用范圍,然后決定是否要將這個對象分配到堆上.
當一個對象在方法中被定義后,對象只在方法內部使用,則認為沒有發生逃逸。
當一個對象在方法中被定義后,它被外部方法所引用,則認為發生逃逸。
//對象發生了逃逸,不會在棧上分配,有可能導致GC STW public StringBuffer append(String s1, String s2) { StringBuffer sb = new StringBuffer(); sb.append(s1); sb.append(s2); return sb; } //對象未發生逃逸 public String append(String s1, String s2) { StringBuffer sb = new StringBuffer(); sb.append(s1); sb.append(s2); return sb.toString(); }
建議:開發中能在方法內部應用對象的,就盡量控制在內部
在 JDK 1.7 版本之后, HotSpot 中默認就已經開啟了逃逸分析,如果使用的是較早的
版本,開發人員則可以通過:
? 選項“ -XX:+DoEscapeAnalysis" 顯式開啟逃逸分析。
? 通過選項“ -XX:+PrintEscapeAnalysis" 查看逃逸分析的篩選結果。
編譯器可以對代碼做如下優化
1.棧上分配:將堆分配轉化為棧分配。如果一個對象在方法內創建,要使指向該對象的引用不會發生逃逸,對象可能是棧上分配的候選
/** * 棧上分配測試(-XX:+DoEscapeAnalysis) * -Xmx128m -Xms128m -XX:+DoEscapeAnalysis -XX:+PrintGC */ public class ObjectStackAllocationTests { public static void main(String[] args) throws InterruptedException { long start = System.currentTimeMillis(); for (int i = 0; i < 10000000; i++) { alloc(); } long end = System.currentTimeMillis(); System.out.println("花費的時間為: " + (end - start) + " ms"); // 為了方便查看堆內存中對象個數,線程 sleep TimeUnit.MINUTES.sleep(5); } private static void alloc() { byte[] data = new byte[10];//未發生逃逸 } }
2.同步鎖消除:
我們知道線程同步是靠犧牲性能來保證數據的正確性,這個過程的代價會非常高。程序 的并發行和性能都會降低。JVM 的 JIT 編譯器可以借助逃逸分析來判斷同步塊所使用的鎖對象是否只能夠被一個線程應用?假如是,那么 JIT 編譯器在編譯這個同步塊的時候就會取消對這部分代碼上加的鎖。這個取消同步的過程就叫同步省略,也叫鎖消除
public class SynchronizedLockTest { public void lock() { Object obj= new Object(); synchronized(obj) { System.out.println(obj); } }
3.標量替換分析
所謂的標量(scalar)一般指的是一個無法再分解成更小數據的數據。例如,Java 中 的原始數據類型就是標量。相對的,那些還可以分解的數據叫做聚合量(Aggregate),Java 中的對象就是聚合量,因為他可以分解成其他聚合量和標量。在 JIT 階段,如果經過逃逸分析,發現一個對象不會被外界訪問的話,那么經過 JIT 優化,就會把這個對象分解成若干個變量來代替。這個過程就是標量替換。
public class ObjectScalarReplaceTests { public static void main(String args[]) { long start = System.currentTimeMillis(); for (int i = 0; i < 10000000; i++) { alloc(); } long end = System.currentTimeMillis(); System.out.println("花費的時間為: " + (end - start) + " ms"); } private static void alloc() { Point point = new Point(1,2); } static class Point { private int x; private int y; public Point(int x,int y){ this.x=x; this.y=y; } } //對于上面代碼,假如開啟了標量替換,那么 alloc 方法的內容就會變為如下形式 private static void alloc() { int x=10; int y=20; }
alloc 方法內部的 Point 對象是一個聚合量,這個聚合量經過逃逸分析后,發現他并沒有逃逸,就被替換成兩個標量了。那么標量替換有什么好處呢?可以大大減少堆內存的占用。因為一旦不需要創建對象了,那么就不再需要分配堆內存了。標量替換為棧上分配 提供了很好的基礎。
1.什么是逃逸分析?
可以有效減少 Java 對象在堆內存中的分配壓力和同步負載的算法
2.逃逸分析有什么優勢、劣勢?
逃逸分析是需要消耗一定的性能去執行分析的,所以說如果方法中的對象全都是處于逃逸狀態,那么就沒有起到優化的作用,從而就白白損失了這部分的性能消耗
到此,關于“JVM內存增強之逃逸分析怎么使用”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。