成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

逃逸分析在 Java 中的應用與優化

開發
逃逸分析技術是JVM用于提高性能以及節省內存的手段,在JVM編譯語境下也就是我們常說的JIT階段,。

逃逸分析技術算是在JVM面試題偶有提及的一個考察點,當然如果你能夠講解JVM工作原理的時候提及這一點,這一定會增加面試官對你的好感,通過對本篇文章的閱讀,你將能夠從容的解決以下幾個面試題:

  • 什么是逃逸分析技術?
  • 逃逸分析技術解決什么問題?帶來什么好處?
  • 如何更好的理解或者運用逃逸分析技術?

什么是逃逸分析

逃逸分析技術是JVM用于提高性能以及節省內存的手段,在JVM編譯語境下也就是我們常說的JIT階段,關于逃逸分析的概念,引用《深入理解Java虛擬機》的說法:

逃逸分析的基本原理是:分析對象動態作用域,當一個對象在方法里面被定義后,它可能被外部方法所引用,例如作為調用參數傳遞到其他方法中,這種稱為方法逃逸;甚至還有可能被外部線程訪問到,譬如賦值給可以在其他線程中訪問的實例變量,這種稱為線程逃逸;從不逃逸、方法逃逸到線程逃逸,稱為對象由低到高的不同逃逸程度。

只要編譯階段判定當前對象并沒有發生逃逸,那么它就會采用棧上分配、標量替換、同步鎖消除等手段提升程序執行性能和節省內存開銷,具體場景還得查看是發生方法逃逸還是線程逃逸。

那么我們又該如何判斷對象是否逃逸呢?我們不妨基于上述的判斷條件來看看這個示例,假設我們現在有一個user類,我們通過UserService進行初始化,那么請問這段代碼是否發生逃逸呢?

public class UserService {

    private User user;

    public void init() {
        user = new User();
        user.setId(RandomUtil.randomInt(10));
        user.setName(RandomUtil.randomString(3));
    }
}

答案當然是肯定的,因為這段代碼方法內所創建的對象被外部的main函數所引用,也就是我們所說的方法逃逸。

再來看看這段代碼,典型的在方法內創建然后被外部函數所引用,也就是所謂的方法逃逸:

public User createUser() {
        User user = new User();
        user.setId(RandomUtil.randomInt(10));
        user.setName(RandomUtil.randomString(3));
        return user;
    }

而這段stringBuffer 已經被其他線程實例所訪問到,也就是典型的線程逃逸:

public static void main(String[] args) throws InterruptedException {
        StringBuffer stringBuffer = new StringBuffer();
        CountDownLatch countDownLatch = new CountDownLatch(3);
        //調用appendStr操作stringBuffer
        new Thread(() -> {
            appendStr(stringBuffer);
            countDownLatch.countDown();
        }).start();

        //循環拼接操作stringBuffer
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                stringBuffer.append("aaa");
            }
            countDownLatch.countDown();
        }).start();
        
        //循環拼接操作stringBuffer
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                stringBuffer.append("aaa");
            }
            countDownLatch.countDown();
        }).start();

        countDownLatch.await();
        System.out.println(stringBuffer);
    }

如何運用到逃逸分析技術

1.棧上分配(針對未逃逸或方法逃逸)

下面這段代碼僅在方法內部完成對象創建或者打印,其對象并沒有被外部方法所引用和暴露,對象就沒有發生逃逸,對于沒有發生逃逸的代碼或者上文中方法逃逸的代碼端,JIT會通過棧上分配減少內存占用和GC壓力。

 Map<Integer, User> userMap = new HashMap<>();


    public int getUserAgeById(int id) {
       User user = new User();
        user.setId(RandomUtil.randomInt(10));
        user.setName(RandomUtil.randomString(3));
        //打印用戶信息
        printUserInfo(user);
    }

2.分離對象或標量替換(針對未逃逸)

如果僅僅是操作未逃逸對象的某些簡單運算,我們同樣可以只在棧幀內使用這個對象,如此JVM就會將這個對象打散,將對象打散為無數個小的局部變量,實現標量替換。

如下所示,這段代碼沒有發生任何逃逸,JVM會避免創建Point ,而是通過棧上創建基本變量完成邏輯操作:

public static void main(String args[]) {
    alloc();
}
class Point {
    private int x;
    private int y;
}
private static void alloc() {
    Point point = new Point(1,2);
    System.out.println("point.x" + point.x + ";point.y" + point.y);
}

進而直接標量替換,直接在棧上分配x和y的值,完成輸出打印。

private static void alloc() {
    int x = 1;
    int y = 2;
    System.out.println("point.x = " + x + "; point.y=" + y);
}

3.同步鎖消除(針對未逃逸線程)

這一點就比較有趣了,我們都知道使用StringBuffer可以保證線程安全,因為其操作函數都有帶synchronized關鍵字,那么請問這段代碼會上鎖嗎?

public void appendStr(int count) {
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < count; i++) {
            sb.append("no: " + i + " ");
        }
    }

答案是不會,因為我們當前操作的StringBuffer 對象并沒有發生線程逃逸,它僅僅在函數內部進行字符串操作,所以針對appendStr內部邏輯,其直接將其優化為StringBuilder:

4.線程逃逸分析的更進一步

請問實例方法調用靜態方法,StringBuffer作為變量傳入,是否發生逃逸,直接創建一個main方法調用這段代碼,方法是否發生逃逸?

public void appendStr(int count) {
        StringBuffer sb = new StringBuffer();
        loop(count, sb);
    }

    private static void loop(int count, StringBuffer sb) {
        for (int i = 0; i < count; i++) {
            sb.append("no: " + i + " ");
        }
    }

答案是發生了方法逃逸,但是沒有發生線程逃逸,但我們的代碼是單線程執行這段代碼,即使StringBuffer 由外部傳入,函數內部依然可以進行鎖消除將其內部的拼接邏輯用StringBuilder進行字符串拼接:

再來看看這段代碼,請問發生逃逸了嗎?

 public void appendStr(int count) {
        StringBuffer sb = new StringBuffer();
        loop(count, sb);
    }

    private static String loop(int count, StringBuffer sb) {
        for (int i = 0; i < count; i++) {
            sb.append("no: " + i + " ");
        }
        return sb.toString();
    }

答案是沒有發生線程逃逸,返回的字符串還是沒有被外部線程操作,所以最終還是被轉為StringBuilder:

而下面這段代碼就是典型的逃逸,可以看到多線程場景下StringBuffer 被多線程共享和訪問,此時JIT優化就會視為對象逃逸:

public static void main(String[] args) throws InterruptedException {
        StringBuffer stringBuffer = new StringBuffer();
        CountDownLatch countDownLatch = new CountDownLatch(3);
        //調用appendStr操作stringBuffer
        new Thread(() -> {
            appendStr(stringBuffer);
            countDownLatch.countDown();
        }).start();

        //循環拼接操作stringBuffer
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                stringBuffer.append("aaa");
            }
            countDownLatch.countDown();
        }).start();

        //循環拼接操作stringBuffer
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                stringBuffer.append("aaa");
            }
            countDownLatch.countDown();
        }).start();

        countDownLatch.await();
        System.out.println(stringBuffer);
    }

    public static void appendStr(StringBuffer stringBuffer) {
        for (int i = 0; i < 10; i++) {
            stringBuffer.append(i);
        }

    }

所以appendStr在判定線程逃逸之后,并沒有將StringBuffer變為StringBuilder:

小結

合理的在棧幀上解決問題可以避免對象逃逸,從而讓JIT盡可能的去進行優化,這一點我想應該是一個Java程序員對于代碼的極致追求了。

責任編輯:趙寧寧 來源: 寫代碼的SharkChili
相關推薦

2018-07-09 15:11:14

Java逃逸JVM

2020-07-21 14:19:18

JVM編程語言

2024-07-23 08:06:19

緩存技術策略

2024-04-07 11:33:02

Go逃逸分析

2022-05-10 11:23:56

漏洞補洞過程入侵檢測

2020-05-13 15:10:04

矩陣乘法深度學習人工智能-

2010-10-11 09:28:07

2023-04-25 08:01:23

JavaQuarkusKubernetes

2010-02-23 10:25:29

2024-03-04 08:00:00

Java開發

2009-03-03 09:56:00

協議分析器WLAN

2020-08-14 10:00:34

Node前端應用

2010-09-02 09:15:33

協議分析器Wi-Fi

2011-06-20 15:55:14

SEO

2011-05-17 10:49:55

OracleSQL Server

2010-03-29 11:06:22

Oracle Spat

2024-07-10 10:45:52

2011-01-21 10:01:07

jQueryjavascriptweb

2009-11-26 10:48:59

PHP驗證碼

2009-05-05 12:00:32

虛擬化部署應用
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 国产乱码精品一区二区三区中文 | 精品乱码一区二区三四区视频 | 免费成人高清在线视频 | 久久日本 | 成人av电影免费在线观看 | 女女百合av大片一区二区三区九县 | 成人精品鲁一区一区二区 | 黄色av网站在线免费观看 | 成年人在线观看视频 | 欧美综合视频 | 国产精品视频免费观看 | 欧美日韩中文字幕在线 | 日韩国产精品一区二区三区 | 中文成人无字幕乱码精品 | 成人av网站在线观看 | 日日操av | 日韩免费三级 | 一级一级毛片免费看 | 国产中文字幕av | 99亚洲国产精品 | 久久之精品| 91丨九色丨国产在线 | 久久综合国产精品 | 成人国内精品久久久久一区 | 亚洲区中文字幕 | 国产视频第一页 | 日韩国产免费观看 | 国产精品久久久久久久久久免费看 | 日韩中文一区二区三区 | 久久精品国产免费一区二区三区 | 成人免费av在线 | h片在线看 | 国产精品久久国产精品 | 亚洲自拍偷拍免费视频 | 一本色道精品久久一区二区三区 | 天天射影院 | 日本久久一区二区三区 | 在线观看精品视频网站 | 国产精品一区二区三区在线 | 成人亚洲一区 | 欧美日韩一 |