众神进入瓦尔哈拉_一时冲动:“通往瓦尔哈拉之路的冒险”
眾神進(jìn)入瓦爾哈拉
通過所有有關(guān)Java 9和Project Jigsaw的討論,我們不應(yīng)忽視Java的另一重大變化。 希望在第10版或第11版中, Valhalla項(xiàng)目能夠?qū)崿F(xiàn)并介紹價(jià)值類型和專業(yè)化。
那么,這是什么一回事,項(xiàng)目進(jìn)展如何,面臨什么挑戰(zhàn)? 幾天前,Oracle的Java語言架構(gòu)師和Valhalla的項(xiàng)目負(fù)責(zé)人Brian Goetz在JVM Language Summit 2015上的一次演講中回答了這些問題。
我們來看一下。
總覽
這篇文章將介紹Goetz演講“冒險(xiǎn)之路到Valhalla”的四個(gè)部分中的三個(gè)。
他以序言開頭,我為那些尚不了解Valhalla項(xiàng)目的人提供了一些補(bǔ)充說明。 Goetz繼續(xù)展示這兩個(gè)原型,其中第一個(gè)原型于去年公開發(fā)布,而第二個(gè)原型僅在兩周前發(fā)布。 由于這篇文章已經(jīng)足夠長了,因此我將不討論他關(guān)于未來實(shí)驗(yàn)的最后一部分。 如果您覺得這個(gè)話題很有趣,那么一定要看整個(gè)演講!
全文中的所有引用均來自幻燈片或逐字記錄。
談話
這里是談話:
(順便說一句,JVMLS團(tuán)隊(duì)在幾個(gè)小時(shí)內(nèi)就將所有討論都在線上獲得了贊譽(yù)!)
如果您可以節(jié)省50分鐘,那就去看吧! 然后,無需閱讀這篇文章。
要點(diǎn)
序幕
Valhalla項(xiàng)目涉及的兩個(gè)主要主題是價(jià)值類型和通用專業(yè)化 。
值類型
前者將允許用戶定義具有相同屬性(如不變性,相等性而不是標(biāo)識(shí))的“類似int”的類型,以及由此產(chǎn)生的性能優(yōu)勢。 它們之前是Java 8的基于值的類 。
(除非另有說明,否則當(dāng)本文章的其余部分討論基元時(shí),將包括值類型。)
通用專業(yè)化
隨著每個(gè)人都聲明自己的原始類型,泛型無法在它們之上工作的事實(shí)(即,沒有ArrayList<int> )引起的問題變得令人無法忍受。 從概念的角度來看,雖然必須對(duì)原語進(jìn)行裝箱,但它具有顯著的性能成本。
首先,存儲(chǔ)對(duì)象而不是基元會(huì)花費(fèi)額外的內(nèi)存(例如,用于對(duì)象標(biāo)頭)。 然后,更糟的是,裝箱會(huì)破壞緩存的局部性 。 當(dāng)CPU緩存一個(gè)Integer數(shù)組時(shí),它僅獲取指向?qū)嶋H值的指針。 提取這些是額外的隨機(jī)內(nèi)存訪問。 當(dāng)CPU主要在等待高速緩存未命中時(shí),這種額外級(jí)別的間接開銷會(huì)付出巨大的代價(jià),并可能破壞并行化。
因此,Valhalla項(xiàng)目的另一個(gè)目標(biāo)是擴(kuò)大參數(shù)多態(tài)性的范圍,以使泛型能夠覆蓋基元。 為了獲得成功,JVM應(yīng)該使用基元而不是用于通用類中的通用字段,參數(shù)和返回值的框。
由于可能的實(shí)現(xiàn)方式,這稱為通用專業(yè)化 。
因此,泛型需要與值類型很好地配合使用,并且原語可以伴隨而來。
泛型的現(xiàn)狀
由于擦除,類型變量被擦除到其邊界,即ArrayList<Integer>實(shí)際上變?yōu)锳rrayList<Object> (或者僅僅是ArrayList )。 這樣的界限必須是所有可能實(shí)例化的超類型。 但是Java在基本類型和引用類型之上沒有類型。
另外,JVM字節(jié)碼指令通常是正交的,即沿同一行分割。 一個(gè)aload或astore只能移動(dòng)引用。 專業(yè)變體具有用于原語,如iload或istore為int 。 沒有字節(jié)碼可以同時(shí)移動(dòng)引用和int 。
因此,類型系統(tǒng)和字節(jié)碼指令集都無法完成生成原語的任務(wù)。 十多年前開發(fā)出仿制藥時(shí),這已廣為人知,作為妥協(xié),決定只是不允許這樣做。
今天的問題來自昨天的解決方案...
兼容性!
當(dāng)然,Valhalla項(xiàng)目下發(fā)生的所有事情都必須向后兼容。 這有幾種形式:
- 二進(jìn)制兼容性:現(xiàn)有字節(jié)碼(即已編譯的類文件)必須繼續(xù)表示同一意思。 這樣可以確保依賴項(xiàng)繼續(xù)工作而無需重新編譯。
- 源代碼兼容性:源文件必須繼續(xù)具有完全相同的含義,因此重新編譯它們一定不能“僅僅因?yàn)檎Z言已更改”而更改任何內(nèi)容。
- 遷移可競爭性:來自不同Java版本的編譯類必須協(xié)同工作,以允許一次遷移一個(gè)依賴項(xiàng)。
另一個(gè)要求是不要使JVM模仿太多的Java語言。 這樣做將迫使其他JVM語言處理Java語言的語義。
原型模型1:使其工作
大約一年前,Goetz和他的同事展示了專業(yè)化的第一個(gè)實(shí)驗(yàn)性實(shí)現(xiàn)。
想法
在此原型中,編??譯器繼續(xù)生成已擦除的類文件,但使用其他類型信息對(duì)其進(jìn)行了擴(kuò)充。
VM會(huì)忽略此信息,但將由專化器使用 ,這是類加載器的新組成部分。 后者將識(shí)別何時(shí)需要帶有原始類型參數(shù)的類,并讓專業(yè)化工具從已刪除但已增強(qiáng)的類文件中即時(shí)生成它。
通過擦除,一個(gè)類的所有通用實(shí)例都使用相同的類文件。 相反,為每種原始類型創(chuàng)建一個(gè)新的類文件稱為specialization 。
細(xì)節(jié)
在該原型中,使用“名稱處理技術(shù)”描述了專門的類。 類名后面附加一個(gè)字符串,該字符串指示哪種類型參數(shù)專用于哪個(gè)原語。 例如, ArrayList${0=I}表示“用第一個(gè)類型變量int實(shí)例化的ArrayList ”。
在專業(yè)化期間,必須更改簽名和字節(jié)碼。 為了正確地做到這一點(diǎn),專門化者需要知道哪些Object出現(xiàn)(所有通用類型都被擦除了)必須專門化為哪種類型。 所需的簽名信息已經(jīng)大部分存在于類文件中,并且原型使用附加的類型元數(shù)據(jù)注釋字節(jié)碼。
從Goetz的8:44起 ,我們給出了幾個(gè)如何進(jìn)行的示例。 他還使用它們來指出這種實(shí)現(xiàn)必須要注意的一些細(xì)節(jié),例如泛型方法的主題。
我知道那是很多快速的揮手。 關(guān)鍵是,這很簡單,但是卻有很多復(fù)雜性。
摘要
該實(shí)驗(yàn)表明,基于類文件元數(shù)據(jù)的即時(shí)專業(yè)化無需更改虛擬機(jī)即可工作。 這些都是重要的成就,但也有不利的弊端。
首先,它需要實(shí)現(xiàn)一組復(fù)雜的細(xì)節(jié)。
其次,也許是最重要的是,它具有有問題的類型系統(tǒng)特征。 在不更改VM的情況下,仍然沒有int和String公共超類型,因此也沒有ArrayList<int>和ArrayList<String>公共超類型。 這意味著無法聲明“ ArrayList任何實(shí)例化”。
第三,這具有可怕的代碼共享屬性。 即使ArrayList<int>和ArrayList<String>大部分代碼是相同的,也可以在ArrayList${0=I}和ArrayList復(fù)制它們。
死亡減少1000點(diǎn)。
原型模型2:搶救通配符
第二個(gè)非常新的原型解決了有問題的類型系統(tǒng)特征。
問題
當(dāng)前,無界通配符表示“類的任何實(shí)例”,例如ArrayList<?>表示“任何ArrayList ”。 它們被大量使用,尤其是庫開發(fā)人員。 在ArrayList<int>和ArrayList<String>是不同類的系統(tǒng)中,通配符可能更為重要,因?yàn)樗鼈儚浐狭怂鼈冎g的鴻溝并“表達(dá)了基本的ArrayList -ness”。
但是,如果我們假設(shè)ArrayList<?>是ArrayList<int>的超類型,那么我們最終會(huì)遇到需要多個(gè)類繼承的情況。 原因是ArrayList<T>擴(kuò)展了AbstractList<T>所以我們也希望ArrayList<int>擴(kuò)展AbstractList<int> 。 現(xiàn)在, ArrayList<int>將擴(kuò)展ArrayList<?>和AbstractList<int> (它們沒有繼承關(guān)系)。
(請(qǐng)注意,與當(dāng)前泛型的區(qū)別在于擦除。在VM中, ArrayList<Integer>和ArrayList<?>是同一類ArrayList,可以自由擴(kuò)展AbstractList。)
根本原因是,雖然ArrayList<?>看起來像是“ any ArrayList ”,但實(shí)際上是ArrayList< ?。 擴(kuò)展Object> ,即“引用類型上的任何ArrayList ”。
想法
原型引入了帶有ref , val和any的通配符新層次結(jié)構(gòu):
- ref包含所有引用類型并替換?
- val包含所有原語和值類型(原型當(dāng)前不支持該值,并且在談話中未提及,但已在Valhalla郵件列表中宣布 )
- any包含ref和val
專用類的多重繼承將通過使用合成接口表示任意類型來解決。 ArrayList<int>將因此擴(kuò)展AbstractList<int>并實(shí)現(xiàn)ArrayList<any> 。
細(xì)節(jié)
層次結(jié)構(gòu)
ArrayList<ref> (即ArrayList<?> )將繼續(xù)為已擦除類型。
為了表示ArrayList<any> ,編譯器將創(chuàng)建一個(gè)接口ArrayList$any 。 它將由ArrayList生成的所有類(例如ArrayList<int>和已擦除的ArrayList )實(shí)現(xiàn),并將擴(kuò)展與超類相對(duì)應(yīng)的所有綜合接口,例如AbstractList$any的AbstractList<any> 。
該接口將包含該類的所有方法的聲明以及其字段的訪問器。 因?yàn)槿匀粵]有對(duì)象和基元的公共超類型,所以必須將其通用參數(shù)和返回類型裝箱。
但是,僅當(dāng)以ArrayList<any>的方式訪問該類時(shí),才需要采取這種繞行的方法,而直接訪問的對(duì)象是例如ArrayList<int> 。 因此,裝箱的性能成本僅由使用通配符的開發(fā)人員承擔(dān),而使用原始專業(yè)化的代碼直接獲得期望的改進(jìn)性能。
它干凈利落地工作。
你不應(yīng)該相信我,事情變得復(fù)雜了。 但這是個(gè)好故事。 我們會(huì)繼續(xù)前進(jìn)。
從Goetz的26:33開始,提供一些示例來解釋一些細(xì)節(jié)。
輔助功能
可訪問性是VM需要更改的區(qū)域。 到目前為止,接口不能具有私有或包可見的方法。 (在Java 9中,可以使用私有默認(rèn)方法,但這在這里無濟(jì)于事,因?yàn)樾枰獙?shí)現(xiàn)。)
一個(gè)聯(lián)系在一起但更老的問題是,即使VM不允許這樣做,外部類及其內(nèi)部類也可以彼此訪問私有成員,因?yàn)閂M不允許這樣做,因?yàn)樗鼈兌际遣幌嚓P(guān)的類。 當(dāng)前,這是通過生成橋接方法(即具有較高可見性的方法,而不是無法訪問的私有成員)進(jìn)行調(diào)用來解決的。
為專門的類創(chuàng)建更多的橋接方法將是可能的,但是很費(fèi)力。 相反,可能的更改是創(chuàng)建類嵌套的概念。 它包含所有專用類和內(nèi)部類,并且VM允許訪問嵌套內(nèi)部的私有成員。
這將使語言的解釋與VM的解釋保持一致,VM的語言將所有專業(yè)化知識(shí)和內(nèi)部類作為一個(gè)單元,而VM的解釋直到現(xiàn)在只看到一堆不相關(guān)的類。
數(shù)組
通用方法也可以采用或返回?cái)?shù)組。 但是,盡管專業(yè)化可以將一個(gè)int到一個(gè)Object上,但是int[]是Object[]并且將每個(gè)單獨(dú)的int裝箱是一個(gè)糟糕的想法。
Arrays 2.0可能在這里有所幫助。 因?yàn)橛懻撔枰臼煜ぴ撎岚?#xff0c;所以我不會(huì)詳細(xì)介紹。 總而言之,看起來他們將解決問題。
摘要
語言的更改在概念上很簡單。 在沒有任何變化的情況下。 類型變量可以用任何修飾,如果需要將實(shí)例分配給通配符類型,則通配符也必須使用任何通配符。
對(duì)于跨越原始類型和引用類型(例如ArrayList<any> )的泛型類,使用通用的超類,所得的編程模型更加合理。 在談到他的團(tuán)隊(duì)將Stream API移植到此原型的經(jīng)驗(yàn)時(shí),Goetz說:
真的很順利。 這正是您想要的。 大約70%的代碼剛剛消失了,因?yàn)樗惺止iT化的原始東西都消失了,然后許多支持手工專門化的復(fù)雜機(jī)制也消失了,三年級(jí)的學(xué)生可以成為一個(gè)簡單的圖書館寫。 因此,我們認(rèn)為這是一個(gè)非常成功的實(shí)驗(yàn)。
與現(xiàn)有代碼的兼容性也很好。
不幸的是,第一個(gè)原型的不良代碼共享屬性仍然存在。 ArrayList<int>和ArrayList<String>仍然是不同的類,它們非常相似,但不共享任何代碼。 下一部分(我將不在本文中介紹)解決該問題,并提出解決該問題的可能方法。
反射
談話非常密集,涉及很多領(lǐng)域。 我們已經(jīng)看到,值類型的引入和期望的性能改進(jìn)需要通用專業(yè)化,因此可以減少甚至防止裝箱。
第一個(gè)原型通過在裝入類時(shí)專門化類來實(shí)現(xiàn)這一目標(biāo),而無需更改JVM。 但是,存在一個(gè)問題,即類的所有實(shí)例都沒有通用的超類型,因?yàn)榛绢愋秃鸵妙愋蛥?shù)會(huì)產(chǎn)生完全不相關(guān)的類。 第二個(gè)原型引入了通配符ref , val和any并使用合成接口來表示any-types。
這一切都非常令人興奮,我等不及要嘗試一下! 不幸的是,我要去度假,所以我不能一會(huì)兒了。 愚蠢的現(xiàn)實(shí)生活……別走了,別毀了一切!
翻譯自: https://www.javacodegeeks.com/2015/08/impulse-adventures-on-the-road-to-valhalla.html
眾神進(jìn)入瓦爾哈拉
總結(jié)
以上是生活随笔為你收集整理的众神进入瓦尔哈拉_一时冲动:“通往瓦尔哈拉之路的冒险”的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 鸡是哺乳动物吗 来这里看专业回答了
- 下一篇: 哈希策略_优化哈希策略的简介