亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

關注性能:宏性能基準測試

2019-11-18 15:08:07
字體:
來源:轉載
供稿:網友

  字節碼提供了應用程序性能的線索
級別:中級

Jack Shirazi (jack@javaPerformanceTuning.com),董事,JavaPerformanceTuning.com
Kirk Pepperdine (kirk@JavaPerformanceTuning.com),首席技術官,JavaPerformanceTuning.com

熱衷于 Java 性能的 Jack Shirazi 和 Kirk Pepperdine ?? JavaPerformanceTuning.com 的董事和 CTO ?? 跟蹤遍布 Internet 上的性能討論,探究是什么在困擾著開發人員。在瀏覽 Usenet 新聞組 comp.lang.java 時,他們碰到了幾個有意思的底層性能調整問題。在 關注性能 的這篇文章中,他們對字節碼作了一些分析,檢驗并回答了其中的一些問題。
盡管沒有專門針對 Java 性能的 Usenet 討論組,但是有許多關于性能調整和優化的討論。這些討論中很大一部分基于從宏性能基準測試中得到的結果,所以在本月的專欄中我們也預備談論有關宏基準測試(microbenchmarking)的好處和不足之處。

前置還后置?
有一個問題非凡引起我們注重:哪一種運算更快:i++ 還是 ++i?在我們瀏覽過的幾乎每一個論壇中都可以看到以不同的形式提出的這個問題。雖然這個問題很簡單,但是看來沒有一個絕對的答案。

首先介紹一下它們的區別,++i 使用前置增量運算符,而 i++ 使用后置增量運算符。雖然它們都增加變量 i,但是前置增量運算符在增量運算之前返回 i 的值,而后置增量運算符在增量運算之后返回值 i。一個簡單的測試程序展示了這種區別:

public class Test {
public static void main(String[] args) {
int PRe = 1;
int post = 1;
System.out.println("++pre = " + (++pre));
System.out.println("post++ = " + (post++));
}
}

運行 Test 類生成以下的輸出:

++pre = 2
post++ = 1

宏基準測試
難道不能試著反復運行每次運算,并觀察哪一種運算有更快的運行時嗎?簡單的回答是能,但是危險在于宏基準測試并不總是測量您想要它們測量的內容。相當多的時候,即時(JIT)編譯器的優化和變化掩蓋了底層性能中所有可檢測的差異。例如,一個這種測試顯示第二個 i++ 運算比第一個 ++i 測試更快。但是改變測試順序顯示正好相反的結果!從這里我們只能得出測試方法有缺陷的結論。進一步的調查表明,這種令人困惑的結果來源于在第一次測試時發生的 HotSpot 優化。這些優化有雙重效果:使第一次運行增加了額外的開銷,并去掉了第二次運行時的解釋成本。

宏基準測試的其他變化,如在發生了 JIT 啟動成本后重復測試,在反復運行時只能給出不確定的結果。它可能告訴我們兩種運算符在速度上沒有區別,但是我們對此不能確定。

iinc 字節碼運算符
Heinz Kabutx 博士在其新聞信 The Java Specialists Newsletter 中,問他的讀者哪一個更快: i++、++i 還是 i+=1?在 Issue 64 中,他報告說有一位讀者用一種簡單的技術回答了他的問題:查看編譯的字節碼。事實上,他考察了四種增量語句:

++i;
i++;
i -= -1;
i += 1;

可以用 Java SDK 所帶的反匯編程序 javap 很輕易地分析編譯的字節碼。這四種增量語句的每一種得到的字節碼都是 iinc 1 1。

iinc 運算符有兩個參數。第一個參數指定變量在 JVM 的局部變量表中的索引,第二個參數指定變量的增量值。

這是不是給了我們一個明確的回答?無論如何,假如不同的源代碼編譯為同樣的字節碼,那么在速度上沒有區別,是不是?

運算符上下文
那么,假如代碼片斷都編譯為同樣的字節碼,使用不同的運算符的意義何在?好,讓我們回過頭看前置增量符和后置增量符。要害的一點是什么時候訪問變量。假如不訪問變量,那么這些運算符之間就沒有什么區別。語句 i++ 和 ++i 本身在功能上是一樣的。不過,語句 j=i++ 和 j=++i 在功能上是 不一樣的。我們需要分析在額外的賦值上下文中的字節碼??紤]這兩個類似的方法:

public static int preIncrement() {
int i = 0, j;
j = ++i;
return j;
}
public static int postIncrement() {
int i = 0, j;
j = i++;
return j;
}

反匯編 preIncrement() 和 postIncrement() 得到下面的字節碼:

Method int preIncrement()
0 iconst_0
1 istore_0
2 iinc 0 1
5 iload_0
6 istore_1
7 iload_1
8 ireturn

Method int postIncrement()
0 iconst_0
1 istore_0
2 iload_0
3 iinc 0 1
6 istore_1
7 iload_1
8 ireturn

現在我們 可以 看到這兩種方法間的區別:preIncrement() 返回 1,而 postIncrement() 返回 0。讓我們分析字節碼,更好地理解這種區別。首先,我們將解釋在反匯編的代碼中可以看到的不同字節碼運算符。

字節碼運算:i=0
iconst_0 運算符將整數 iconst_0 推到堆棧上。要完全理解這一點,請記住 JVM 模擬一個基于堆棧的 CPU(假如您以前沒接觸過堆棧,請參閱 java.util.Stack 類文檔)。JVM 在需要以后對某些東西進行操作時,先將它們推到堆棧中,在預備對它們進行操作時彈出它們。

在 Java 語言中有幾種不同的數據類型,對于不同的數據類型有不同的字節碼運算符。對于某些特定的優化,值 -1、0、1、2、3、4 和 5 都有專門的字節碼。假如我們不是處理這些值,那么編譯器會生成 bipush 字節碼運算,將一個特定的整數推到堆棧上(例如,假如方法的第一條語句是 int i = -2,那么第一個字節碼將會 bipush -2)。

下一條語句 istore_0 看上去可能像另一個處理整數 -1 到 5 的非凡字節碼,但是事實上,這次 _0 指向一個到局部變量表的索引。JVM 維護一個局部于方法的變量表,字節碼 istore 在堆棧的頂部彈出這個值,并將這個值儲存到局部變量表中。在這里我們用的是 istore_0,所以這個值儲存在表的索引 0 處。

所有這些解釋針對的是“i=0”的Java 字節碼,它被轉換為字節碼:

0 iconst_0
1 istore_0

更多的字節碼運算
現在我們知道了堆棧和局部變量表,我們可以更快地討論其他字節碼。正如我們前面說的,字節碼 iinc 0 1 在局部變量表索引 0 處增量值 1,iload_0 將局部變量表索引 0 處的值推到椎棧中,而 ireturn 從堆棧中彈出這個值,并將它推到調用方法的操作數堆棧上。下面的表 1 概括了字節碼。

表 1. 字節碼

字節碼 描述
iconst_0 將 0 推到堆棧中
iconst_1 將 1 推到堆棧中
istore_0 從堆棧中彈出這個值,并將它存儲到局部變量表的索引 0 處
istore_1 從堆棧中彈出這個值,并將它存儲到局部變量表的索引 1 處
iload_0 將局部變量表索引 0 處的值推到堆棧中
iload_1 將局部變量表索引 1 處的值推到堆棧中
iadd 從操作數堆棧中彈出兩個整數并讓它們相加。將得到的整數推回堆棧中
iinc 0 1 局部變量表索引 0 處的變量加 1
ireturn 從堆棧中彈出值并將它推到調用方法的操作數棧中。退出方法

比較方法
現在,讓我們再看一下這些反匯編的字節碼。我們將用 lvar 表示局部變量表,就像它是一個 Java 數組,并對字節碼加上注釋:

Method int preIncrement()
0 iconst_0 //push 0 onto the stack
1 istore_0 //pop 0 from the stack and store it at lvar[0], i.e. lvar[0]=0
2 iinc 0 1 //lvar[0] = lvar[0]+1 which means that now lvar[0]=1
5 iload_0 //push lvar[0] onto the stack, i.e. push 1
6 istore_1 //pop the stack (value at top is 1) and store at it lvar[1], i.e. lvar[1]=1
7 iload_1 //push lvar[1] onto the stack, i.e. push 1
8 ireturn //pop the stack (value at top is 1) to the invoking method i.e. return 1

Method int postIncrement()
0 iconst_0 //push 0 onto the stack
1 istore_0 //pop 0 from the stack and store it at lvar[0], i.e. lvar[0]=0
2 iload_0 //push lvar[0] onto the stack, i.e. push 0
3 iinc 0 1 //lvar[0] = lvar[0]+1 which means that now lvar[0]=1
6 istore_1 //pop the stack (value at top is 0) and store at it lvar[1], i.e. lvar[1]=0
7 iload_1 //push lvar[1] onto the stack, i.e. push 0
8 ireturn //pop the stack (value at top is 0) to the invoking method i.e. return 0

現在,希望您能更清楚地了解所發生的事情,以及方法之間的一些功能差別。惟一的差別是兩個方法的第三個和第四個字節碼交換了。注釋的字節碼清楚表明,在 postIncrement() 方法中,iinc 運算完全是多余的,因為從這一點起,不再使用被更新的局部變量元素 lvar[0]。對于這個特定的方法,一個優化 JIT 編譯程序可以完全去掉這種字節碼運算。所以在這種特定情形中,postIncrement() 方法可能有比 preIncrement() 操作更少的字節碼運算,從而使它更加高效。但是在大多數使用后置增量運算符的情況下,增量運算是不能優化的。

那么誰更快呢?
我們學到了什么?是的,假如語句只有 ++i 和 i++ ,那么它們之間沒有區別。只有在存在額外的賦值時,編譯的字節碼才會有區別。

在賦值的上下文中,比較前置增量運算符或者后置增量運算符的使用有可能得到不同的運行時。但是使用哪種運算的功能結果都不太可能是一樣的。記住,在我們這里的例子里,方法實際上返回不同的值,它取決于我們是使用前置增量運算符還是后置增量運算符。在一個普通程序中,其中一種變化可能會成為一個缺陷。

結束語
在過去,我們可以根據一組運算的語言表達對它們的成本進行測量。這是因為這些運算到底層運行時環境的轉換總是靜態的,這在 Java 運行時中是不成立的。Java 運行時可以動態優化運行的代碼,這是一種非凡強大的功能。盡管這種功能還沒有使我們完全不能進行宏性能基準測試,但是它導致我們在使用這種技術時需要更加當心。

參考資料

閱讀 Jack Shirazi 和 Kirk Pepperdine 的全部 關注性能 系列。

Greg Travis 的“如何封鎖您的(或打開別人的) Java 代碼”(developerWorks,2001 年 5 月)提供了有關反編譯一個 Java 類文件的信息。

利用 The Jikes Research Virtual Machine (developerWorks,2000 年 2 月)了解更多有關 IBM 對高性能 JVM 的研究。

Click 博士在 JavaOne 2003 上展示了 High Performance Computing with HotSpot Server Compiler (PDF)。

The Java HotSpot Virtual Machine, v1.4.1 (java.sun.com,2002 年 9 月)是有關 JVM HotSpot 技術的官方白皮書。

Jack Shirazi 的“Micro-Tuning Step-by-Step”(ONJava,2002 年 3 月)提供了對宏性能基準測試的實用建議。

在 developerWorks Java 技術專區 可以找到數百篇有關 Java 編程各個方面的文章。

關于作者
Jack Shirazi 是 JavaPerformanceTuning.com 的董事,也是 Java Performance Tuning (O′Reilly)一書的作者。

Kirk Pepperdine 是 Java Performance Tuning.com 的首席技術官,并且在過去 15 年一直關注對象技術和性能調優。Kirk 是 ANT Developer′s Handbook 一書的合著者。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
国产精品久久国产精品99gif| 丝袜美腿亚洲一区二区| 日韩中文在线视频| 国产成人精品日本亚洲| 欧美老女人bb| 亚洲自拍偷拍视频| 欧美亚洲视频在线观看| 亚洲电影成人av99爱色| 2019中文字幕在线观看| 日韩精品视频在线观看免费| 亚洲国产成人久久综合| 精品久久香蕉国产线看观看亚洲| 精品国产鲁一鲁一区二区张丽| 97av在线视频免费播放| 国内精品美女av在线播放| 久久久免费观看| 亚洲自拍高清视频网站| 中文字幕欧美日韩va免费视频| 亚洲a∨日韩av高清在线观看| 亚洲欧美日韩网| 国产精品劲爆视频| 国语自产精品视频在线看| 亚洲一区二区福利| 欧美极品美女视频网站在线观看免费| 欧美日韩亚洲精品一区二区三区| 91九色精品视频| 国产97色在线| 久久精品电影网站| 欧美午夜丰满在线18影院| 麻豆乱码国产一区二区三区| 欧洲s码亚洲m码精品一区| 国语自产精品视频在线看| 亚洲品质视频自拍网| 综合国产在线视频| 2019中文字幕全在线观看| 国产精品久久久久久久久粉嫩av| 尤物九九久久国产精品的分类| 亚洲欧美第一页| 国产精品va在线播放| 97av在线视频免费播放| 日韩欧美在线视频观看| 日韩电影免费在线观看中文字幕| 国产成人啪精品视频免费网| 欧美成人激情视频| 福利一区视频在线观看| 欧美麻豆久久久久久中文| 精品久久久香蕉免费精品视频| 国产精品视频26uuu| 精品成人69xx.xyz| 亚洲图片在区色| 亚洲男人的天堂在线| 国产精品成av人在线视午夜片| 国产午夜精品美女视频明星a级| 欧美野外猛男的大粗鳮| 欧美午夜宅男影院在线观看| 黑人巨大精品欧美一区免费视频| 久久99国产精品自在自在app| 欧美性猛交xxxx乱大交3| 国产精品video| 国产成人福利夜色影视| 国产亚洲欧美视频| 日韩电影在线观看永久视频免费网站| 日韩中文字幕在线视频播放| 日韩精品欧美国产精品忘忧草| 亚洲国产精品久久久久秋霞蜜臀| 岛国av午夜精品| 在线日韩第一页| 国产精品第一区| 91精品国产高清自在线看超| 91香蕉亚洲精品| 欧美精品久久久久久久免费观看| 精品亚洲一区二区三区在线播放| 亚洲欧美综合精品久久成人| 日韩亚洲欧美成人| 欧美大尺度在线观看| 九九久久精品一区| 色噜噜国产精品视频一区二区| 日韩欧美在线第一页| 91美女高潮出水| 亚洲国产成人av在线| 日韩在线视频观看正片免费网站| 青青久久av北条麻妃海外网| 欧美性猛交xxxx乱大交| 欧美自拍视频在线观看| 97视频人免费观看| 中文字幕在线视频日韩| 亚洲欧美一区二区三区情侣bbw| 亚洲色图偷窥自拍| 日本欧美一二三区| 91久久在线播放| 久久av资源网站| 国产精品视频自拍| 精品国产欧美成人夜夜嗨| 日本最新高清不卡中文字幕| 欧美在线不卡区| 亚洲在线免费视频| 国产精品88a∨| 尤物九九久久国产精品的特点| 欧美伦理91i| 日韩在线免费高清视频| 久久免费视频在线观看| 欧美激情精品久久久久| 日本精品视频在线观看| 欧美成人精品xxx| 国产一区二区三区视频在线观看| 国产精品∨欧美精品v日韩精品| 国产mv久久久| 国产成人精品日本亚洲| 欧美日韩性生活视频| 中文在线不卡视频| 日韩中文字幕在线| 久久久999精品视频| 这里只有精品视频| 1769国产精品| 日韩成人激情影院| 98精品国产自产在线观看| 国产日韩精品电影| 亚洲精品少妇网址| 久久伊人精品一区二区三区| 色阁综合伊人av| 操人视频在线观看欧美| 中文字幕欧美日韩精品| 日韩欧美中文免费| 97久久国产精品| 国产一区二区欧美日韩| 色综合久久久888| 久久综合色88| 97超碰蝌蚪网人人做人人爽| 亚洲影院色在线观看免费| 国产精品一区二区三区久久久| 国产精品一二三在线| 亚洲日韩中文字幕在线播放| 中文字幕日韩综合av| 精品国产拍在线观看| 久久香蕉国产线看观看网| 精品久久香蕉国产线看观看亚洲| 亚洲图片欧洲图片av| 97人人爽人人喊人人模波多| 欧美激情亚洲自拍| 精品视频在线观看日韩| 欧美多人乱p欧美4p久久| 免费97视频在线精品国自产拍| 日本视频久久久| 亚洲网站视频福利| 一本色道久久综合亚洲精品小说| 海角国产乱辈乱精品视频| 久久久久日韩精品久久久男男| 日韩视频亚洲视频| 欧美日在线观看| 欧美激情国产高清| 日韩av在线影院| 亚洲精品福利免费在线观看| 欧美又大粗又爽又黄大片视频| 久久露脸国产精品| 精品日本美女福利在线观看| 91美女高潮出水| 国产精品久久婷婷六月丁香| 国产成+人+综合+亚洲欧美丁香花| 中文字幕国产精品久久| 日韩av在线一区二区| 亚洲最大成人免费视频| 久久99视频免费| 久久福利视频导航| 伊人久久男人天堂|