亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Java自動裝箱性能怎么用

發布時間:2022-01-06 22:27:50 來源:億速云 閱讀:211 作者:iii 欄目:編程語言

本篇內容主要講解“Java自動裝箱性能怎么用”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“Java自動裝箱性能怎么用”吧!

Java 的基本數據類型(int、double、 char)都不是對象。但由于很多Java代碼需要處理的是對象(Object),Java給所有基本類型提供了包裝類(Integer、Double、Character)。有了自動裝箱,你可以寫如下的代碼

Character boxed = 'a'; char unboxed = boxed;

編譯器自動將它轉換為

Character boxed = Character.valueOf('a'); char unboxed = boxed.charValue();

然而,Java虛擬機不是每次都能理解這類過程,因此要想得到好的系統性能,避免不必要的裝箱很關鍵。這也是 OptionalInt 和 IntStream 等特殊類型存在的原因。在這篇文章中,我將概述JVM很難消除自動裝箱的一個原因。

實例

例如,我們想要計算任意一類數據的編輯距離(Levenshtein距離),只要這些數據可以被看作一個序列:

public class Levenshtein{ private final Function> asList;  public Levenshtein(Function> asList) { this.asList = asList; }  public int distance(T a, T b) { // Wagner-Fischer algorithm, with two active rows  List aList = asList.apply(a); List bList = asList.apply(b);  int bSize = bList.size(); int[] row0 = new int[bSize + 1]; int[] row1 = new int[bSize + 1];  for (int i = 0; i row0[i] = i; }  for (int i = 0; i < bSize; ++i) { U ua = aList.get(i); row1[0] = row0[0] + 1;  for (int j = 0; j < bSize; ++j) { U ub = bList.get(j); int subCost = row0[j] + (ua.equals(ub) ? 0 : 1); int delCost = row0[j + 1] + 1; int insCost = row1[j] + 1; row1[j + 1] = Math.min(subCost, Math.min(delCost, insCost)); }  int[] temp = row0; row0 = row1; row1 = temp; }  return row0[bSize]; } }

只要兩個對象可以被看作List,這個類就可以計算它們的編輯距離。如果想計算String類型的距離,那么就需要把String轉變為List類型:

public class StringAsList extends AbstractList{ private final String str;  public StringAsList(String str) { this.str = str; }  @Override public Character get(int index) { return str.charAt(index); // Autoboxing! }  @Override public int size() { return str.length(); } }  ...  Levenshteinlev = new Levenshtein<>(StringAsList::new); lev.distance("autoboxing is fast", "autoboxing is slow"); // 4

由于Java泛型的實現方式,不能有List類型,所以要提供List和裝箱操作。(注:Java10中,這個限制也許會被取消。)

為了查看代碼熱路徑(hot  path)上的結果,JMH集成了Linux工具perf,可以查看最熱代碼塊的JIT編譯結果。(要想查看匯編代碼,需要安裝hsdis插件。我在 AUR上提供了下載,Arch用戶可以直接獲取。)在JMH命令行添加 -prof perfasm 命令,就可以看到結果:

為了測試 distance() 方法的性能,需要做基準測試。Java中微基準測試很難保證準確,但幸好OpenJDK提供了JMH(Java  Microbenchmark  Harness),它可以幫我們解決大部分難題。如果感興趣的話,推薦大家閱讀文檔和實例;它會很吸引你。以下是基準測試:

@State(Scope.Benchmark) public class MyBenchmark { private Levenshtein lev = new Levenshtein<>(StringAsList::new);  @Benchmark @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.NANOSECONDS) public int timeLevenshtein() { return lev.distance("autoboxing is fast", "autoboxing is slow"); } }

(返回方法的結果,這樣JMH就可以做一些操作讓系統認為返回值會被使用到,防止冗余代碼消除影響了結果。)

以下是結果:

$ java -jar target/benchmarks.jar -f 1 -wi 8 -i 8 # JMH 1.10.2 (released 3 days ago) # VM invoker: /usr/lib/jvm/java-8-openjdk/jre/bin/java # VM options: # Warmup: 8 iterations, 1 s each # Measurement: 8 iterations, 1 s each # Timeout: 10 min per iteration # Threads: 1 thread, will synchronize iterations # Benchmark mode: Average time, time/op # Benchmark: com.tavianator.boxperf.MyBenchmark.timeLevenshtein  # Run progress: 0.00% complete, ETA 00:00:16 # Fork: 1 of 1 # Warmup Iteration 1: 1517.495 ns/op # Warmup Iteration 2: 1503.096 ns/op # Warmup Iteration 3: 1402.069 ns/op # Warmup Iteration 4: 1480.584 ns/op # Warmup Iteration 5: 1385.345 ns/op # Warmup Iteration 6: 1474.657 ns/op # Warmup Iteration 7: 1436.749 ns/op # Warmup Iteration 8: 1463.526 ns/op Iteration 1: 1446.033 ns/op Iteration 2: 1420.199 ns/op Iteration 3: 1383.017 ns/op Iteration 4: 1443.775 ns/op Iteration 5: 1393.142 ns/op Iteration 6: 1393.313 ns/op Iteration 7: 1459.974 ns/op Iteration 8: 1456.233 ns/op  Result "timeLevenshtein": 1424.461 &plusmn;(99.9%) 59.574 ns/op [Average] (min, avg, max) = (1383.017, 1424.461, 1459.974), stdev = 31.158 CI (99.9%): [1364.887, 1484.034] (assumes normal distribution)  # Run complete. Total time: 00:00:16  Benchmark Mode Cnt Score Error Units MyBenchmark.timeLevenshtein avgt 8 1424.461 &plusmn; 59.574 ns/op

分析

為了查看代碼熱路徑(hot  path)上的結果,JMH集成了Linux工具perf,可以查看最熱代碼塊的JIT編譯結果。(要想查看匯編代碼,需要安裝hsdis插件。我在 AUR上提供了下載,Arch用戶可以直接獲取。)在JMH命令行添加 -prof perfasm 命令,就可以看到結果:

$ java -jar target/benchmarks.jar -f 1 -wi 8 -i 8 -prof perfasm ... cmp $0x7f,%eax jg 0x00007fde989a6148 ;*if_icmpgt ; - java.lang.Character::valueOf@3 (line 4570) ; - com.tavianator.boxperf.StringAsList::get@8 (line 14) ; - com.tavianator.boxperf.StringAsList::get@2; (line 5) ; - com.tavianator.boxperf.Levenshtein::distance@121 (line 32) cmp $0x80,%eax jae 0x00007fde989a6103 ;*aaload ; - java.lang.Character::valueOf @ 10 (line 4571) ; - com.tavianator.boxperf.StringAsList::get@8 (line 14) ; - com.tavianator.boxperf.StringAsList::get @ 2 (line 5) ; - com.tavianator.boxperf.Levenshtein::distance@121 (line 32) ...

輸出內容很多,但上面的一點內容就說明裝箱沒有被優化。為什么要和0x7f/0&times;80的內容做比較呢?原因在于Character.valueOf()的取值來源:

private static class CharacterCache { private CharacterCache(){}  static final Character cache[] = new Character[127 + 1];  static { for (int i = 0; i < cache.length; i++) cache[i] = new Character((char)i); } }  public static Character valueOf(char c) { if (c return CharacterCache.cache[(int)c]; } return new Character(c); }

可以看出,Java語法標準規定前127個char的Character對象放在緩沖池中,Character.valueOf()的結果在其中 時,直接返回緩沖池的對象。這樣做的目的是減少內存分配和垃圾回收,但在我看來這是過早的優化。而且它妨礙了其他優化。JVM無法確定  Character.valueOf(c).charValue() ==  c,因為它不知道緩沖池的內容。所以JVM從緩沖池中取了一個Character對象并讀取它的值,結果得到的就是和 c 一樣的內容。

解決方法

解決方法很簡單:

@ @ -11,7 +11,7 @ @ public class StringAsList extends AbstractList {  @Override public Character get(int index) { - return str.charAt(index); // Autoboxing! + return new Character(str.charAt(index)); }

@Override

用顯式的裝箱代替自動裝箱,就避免了調用Character.valueOf(),這樣JVM就很容易理解代碼:

private final char value;  public Character(char value) { this.value = value; }  public char charValue() { return value; }

雖然代碼中加了一個內存分配,但JVM能理解代碼的意義,會直接從String中獲取char字符。性能提升很明顯:

$ java -jar target/benchmarks.jar -f 1 -wi 8 -i 8 ... # Run complete. Total time: 00:00:16  Benchmark Mode Cnt Score Error Units MyBenchmark.timeLevenshtein avgt 8 1221.151 &plusmn; 58.878 ns/op

速度提升了14%。用 -prof perfasm 命令可以顯示,改進以后是直接從String中拿到char值并在寄存器中比較的:

movzwl 0x10(%rsi,%rdx,2),%r11d ;*caload
; - java.lang.String::charAt@27 (line 648)
; - com.tavianator.boxperf.StringAsList::get@9 (line 14)
; - com.tavianator.boxperf.StringAsList::get @ 2 (line 5)
; - com.tavianator.boxperf.Levenshtein::distance@121 (line 32)
cmp %r11d,%r10d
je 0x00007faa8d404792 ;*if_icmpne
; - java.lang.Character::equals@18 (line 4621)
; - com.tavianator.boxperf.Levenshtein::distance@137 (line 33)

到此,相信大家對“Java自動裝箱性能怎么用”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

丘北县| 五华县| 班玛县| 临江市| 汪清县| 金寨县| 沙田区| 柳江县| 新乐市| 读书| 新干县| 开鲁县| 赤峰市| 鸡东县| 姜堰市| 吴堡县| 南溪县| 临潭县| 白河县| 康马县| 蓬安县| 通渭县| 乌拉特后旗| 山西省| 新丰县| 鸡泽县| 景泰县| 陵川县| 赤水市| 罗江县| 抚顺市| 吐鲁番市| 峨眉山市| 建阳市| 大化| 苍梧县| 万全县| 玉溪市| 滨海县| 钟祥市| 白水县|