本篇內(nèi)容主要講解“Java對(duì)象怎么在棧上分配內(nèi)存”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實(shí)用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“Java對(duì)象怎么在棧上分配內(nèi)存”吧!
創(chuàng)新互聯(lián)是一家集網(wǎng)站建設(shè),清河企業(yè)網(wǎng)站建設(shè),清河品牌網(wǎng)站建設(shè),網(wǎng)站定制,清河網(wǎng)站建設(shè)報(bào)價(jià),網(wǎng)絡(luò)營銷,網(wǎng)絡(luò)優(yōu)化,清河網(wǎng)站推廣為一體的創(chuàng)新建站企業(yè),幫助傳統(tǒng)企業(yè)提升企業(yè)形象加強(qiáng)企業(yè)競爭力。可充分滿足這一群體相比中小企業(yè)更為豐富、高端、多元的互聯(lián)網(wǎng)需求。同時(shí)我們時(shí)刻保持專業(yè)、時(shí)尚、前沿,時(shí)刻以成就客戶成長自我,堅(jiān)持不斷學(xué)習(xí)、思考、沉淀、凈化自己,讓我們?yōu)楦嗟钠髽I(yè)打造出實(shí)用型網(wǎng)站。
1 逃逸分析
JVM中高深的優(yōu)化技術(shù),如同類繼承關(guān)系分析,該技術(shù)并非直接去優(yōu)化代碼,而是一種為其他優(yōu)化措施提供依據(jù)的分析技術(shù)。
分析對(duì)象的動(dòng)態(tài)作用域,當(dāng)某對(duì)象在方法里被定義后,它可能
方法逃逸
被外部方法引用,例如作為參數(shù)傳遞給其他方法
線程逃逸
被外部線程訪問,例如賦值給可以在其他線程中訪問的實(shí)例變量
所以 Java 對(duì)象由低到高的逃逸程度即為:
不逃逸 =》
方法逃逸 =》
線程逃逸
若能確定一個(gè)對(duì)象
不會(huì)逃逸到方法或線程外(即其它方法、線程無法訪問到該對(duì)象)
或逃逸程度較低(只逃逸出方法而不逃逸出線程)
則可為該對(duì)象實(shí)例采取不同程度的優(yōu)化方案。
2 優(yōu)化方案
2.1 棧上分配(Stack Allocations)
由于復(fù)雜度等原因,HotSpot中目前暫時(shí)還沒有做這項(xiàng)優(yōu)化,但一些其他的虛擬機(jī)(如Excelsior JET)使用了該優(yōu)化。
JVM的GC模塊會(huì)回收堆中不再使用的對(duì)象,但如下回收動(dòng)作
標(biāo)記篩選出可回收對(duì)象
回收和整理內(nèi)存
都需耗費(fèi)大量資源。
若確定一個(gè)對(duì)象不會(huì)逃逸出線程,那讓該對(duì)象在棧上分配內(nèi)存就是個(gè)不錯(cuò)主意,對(duì)象所占用內(nèi)存空間就可隨棧幀出棧而銷毀。
在一般應(yīng)用中,完全不會(huì)逃逸的局部對(duì)象和不會(huì)逃逸出線程的對(duì)象所占比例很大,若能使用棧上分配,則大量對(duì)象就會(huì)隨方法結(jié)束而自動(dòng)銷毀,GC系統(tǒng)壓力會(huì)下降很多。
棧上分配可支持方法逃逸,但不能支持線程逃逸。
2.2 標(biāo)量替換(Scalar Replacement)
2.2.1 標(biāo)量
若一個(gè)數(shù)據(jù)已經(jīng)無法再分解成更小數(shù)據(jù),JVM中的原始數(shù)據(jù)類型(如 int、long 等數(shù)值類型及 reference 類型)都不能再進(jìn)一步分解,這些數(shù)據(jù)即為標(biāo)量。
2.2.2 聚合量
若一個(gè)數(shù)據(jù)可繼續(xù)分解,則稱為聚合量(Aggregate),比如 Java 對(duì)象就是聚合量。
2.2.3 標(biāo)量替換
把一個(gè)Java對(duì)象拆散,根據(jù)程序訪問情況,將其用到的成員變量恢復(fù)為原始類型來訪問。
假如逃逸分析能證明一個(gè)對(duì)象不會(huì)被方法外部訪問,并且該對(duì)象可被分解,那么程序真正執(zhí)行時(shí)將可能不去創(chuàng)建該對(duì)象,而改為直接創(chuàng)建它的若干個(gè)被這方法使用的成員變量。
將對(duì)象拆分后:
可讓對(duì)象的成員變量在棧上 (棧上存儲(chǔ)的數(shù)據(jù),很大概率會(huì)被JVM分配至物理機(jī)器的高速寄存器中存儲(chǔ))分配和讀寫
為后續(xù)進(jìn)步優(yōu)化創(chuàng)建條件
2.2.4 適用場景
標(biāo)量替換可視為棧上分配一種特例,實(shí)現(xiàn)更簡單(不用考慮對(duì)象完整結(jié)構(gòu)的分配),但對(duì)逃逸程度的要求更高,它不允許對(duì)象逃逸出方法范圍內(nèi)。
2.3 同步消除(Synchronization Elimination)
線程同步是個(gè)相對(duì)耗時(shí)的過程,若逃逸分析能確定一個(gè)變量不會(huì)逃逸出線程,即不會(huì)被其他線程訪問,則該變量的讀寫肯定不會(huì)有線程競爭, 也可安全消除對(duì)該變量實(shí)施的同步措施。
逃逸分析的論文在1999年就已發(fā)表,但到JDK 6,HotSpot才開始初步支持逃逸分析,至今該也尚未成熟,主要因?yàn)樘右莘治龅挠?jì)算成本高到無法保證帶來的性能收益會(huì)高于它的消耗。要百分百準(zhǔn)確判斷一個(gè)對(duì)象是否會(huì)逃逸,需進(jìn)行一系列復(fù)雜數(shù)據(jù)流敏感的過程間分析,才能確定程序各個(gè)分支執(zhí)行時(shí)對(duì)此對(duì)象的影響。過程間分析這種大壓力的分析算法正是即時(shí)編譯的弱項(xiàng)。試想,若逃逸分析完畢后發(fā)現(xiàn)幾乎找不到幾個(gè)不逃逸的對(duì)象, 那這些運(yùn)行期耗用的時(shí)間就白費(fèi)了,所以目前JVM只能采用不那么準(zhǔn)確,但時(shí)間壓力相對(duì)較小的算法來完成分析。
C和C++原生支持棧上分配(不使用new即可),靈活運(yùn)用棧內(nèi)存方面,Java的確是弱勢群體。
在現(xiàn)在仍處于實(shí)驗(yàn)階段的Valhalla項(xiàng)目,設(shè)計(jì)了新的inline關(guān)鍵字用于定義Java的內(nèi)聯(lián)類型, 對(duì)標(biāo)C#的值類型。有了該標(biāo)識(shí)與約束,以后逃逸分析做起來就會(huì)簡單很多。
3 代碼實(shí)戰(zhàn)驗(yàn)證
3.1 全無優(yōu)化的代碼
public int test(int x) { int xx = x + 2; Point p = new Point(xx, 42); return p.getX(); }
3.2 優(yōu)化step1:內(nèi)聯(lián)構(gòu)造器和getX()方法
public int test(int x) { int xx = x + 2; // 在堆中分配P對(duì)象 Point p = point_memory_alloc(); // Point構(gòu)造器被內(nèi)聯(lián)后 p.x = xx; p.y = 42; // Point::getX()被內(nèi)聯(lián)后 return p.x; }
優(yōu)化step2:標(biāo)量替換
逃逸分析后,發(fā)現(xiàn)在整個(gè)test()方法的范圍內(nèi)Point對(duì)象實(shí)例不會(huì)發(fā)生任何程度逃逸, 便可對(duì)它進(jìn)行標(biāo)量替換:把其內(nèi)部的x和y直接置換出來,分解為test()方法內(nèi)的局部變量,從而避免了Point對(duì)象實(shí)例的創(chuàng)建
public int test(int x) { int xx = x + 2; int px = xx; int py = 42 return px; }
step3:無效代碼消除
數(shù)據(jù)流分析,發(fā)現(xiàn)py的值其實(shí)對(duì)方法不會(huì)造成任何影響,那就可以放心地去做無效代碼消除得到最終優(yōu)化結(jié)果,如下所示:
public int test(int x) { return x + 2; }
觀察測試結(jié)果,實(shí)施逃逸分析后的程序在MicroBenchmarks中往往能得到不錯(cuò)的成績,但在實(shí)際應(yīng)用程序中,尤其是大型程序中反而發(fā)現(xiàn)實(shí)施逃逸分析可能出現(xiàn)效果不穩(wěn)定,或分析過程耗時(shí)但卻無法有效判別出非逃逸對(duì)象而導(dǎo)致性能(即時(shí)編譯的收益)下降,所以曾經(jīng)在很長的一段時(shí)間,即使是服務(wù)端編譯器,也默認(rèn)不開啟逃逸分析(從JDK 6 Update 23開始,服務(wù)端編譯器中開始才默認(rèn)開啟逃逸分析。),甚至在某些版本(如JDK 6 Update 18)中還曾完全禁止這項(xiàng)優(yōu)化,一直到JDK 7時(shí)這項(xiàng)優(yōu)化才成為服務(wù)端編譯器默認(rèn)開啟的選項(xiàng)。
若有需要或確認(rèn)對(duì)程序有益,可使用參數(shù):
-XX:+DoEscapeAnalysis 手動(dòng)開啟逃逸分析
開啟后可通過參數(shù):
-XX:+PrintEscapeAnalysis 查看分析結(jié)果
有逃逸分析支持后,用戶可使用如下參數(shù):
-XX:+EliminateAllocations 開啟標(biāo)量替換
+XX:+EliminateLocks 開啟同步消除
-XX:+PrintEliminateAllocations 查看標(biāo)量的替換情況
到此,相信大家對(duì)“Java對(duì)象怎么在棧上分配內(nèi)存”有了更深的了解,不妨來實(shí)際操作一番吧!這里是創(chuàng)新互聯(lián)網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!
分享標(biāo)題:Java對(duì)象怎么在棧上分配內(nèi)存
網(wǎng)站地址:http://www.chinadenli.net/article12/jcosdc.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供做網(wǎng)站、自適應(yīng)網(wǎng)站、App設(shè)計(jì)、品牌網(wǎng)站設(shè)計(jì)、云服務(wù)器、網(wǎng)頁設(shè)計(jì)公司
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)