Kotlin內(nèi)存陷阱inline使用技巧示例詳解
引言
inline
,翻譯過來為 內(nèi)聯(lián) ,在 Kotlin
中,一般建議用于 高階函數(shù)
中,目的是用來彌補(bǔ)其運(yùn)行時的 額外開銷。
其原理也比較簡單,在調(diào)用時將我們的代碼移動到調(diào)用處使用,從而降低方法調(diào)用時的 棧幀 層級。
棧幀: 指的是虛擬機(jī)在進(jìn)行方法調(diào)用和方法執(zhí)行時的數(shù)據(jù)結(jié)構(gòu),每一個棧幀里都包含了相應(yīng)的數(shù)據(jù),比如 局部參數(shù),操作數(shù)棧等等。
Jvm在執(zhí)行方法時,每執(zhí)行一個方法會產(chǎn)生一個棧幀,隨后將其保存到我們當(dāng)前線程所對應(yīng)的棧里,方法執(zhí)行完畢時再將此方法出棧,
所以內(nèi)聯(lián)后就相當(dāng)于省了一個棧幀調(diào)用。
如果上述描述中,你只記住了后半句,降低棧幀 ,那么此時你可能已經(jīng)陷入了一個使用陷阱?
錯誤示例
如下截圖中所示,我們隨便創(chuàng)建了一個方法,并增加了 inline
關(guān)鍵字:
觀察截圖會發(fā)現(xiàn),此時IDE已經(jīng)給出了提示,它建議你移除 inline
, Why? 為什么呢???
不是說內(nèi)聯(lián)可以提高性能嗎,那么不應(yīng)該任何方法都應(yīng)該加 inline
提高性能嗎?(就是這么倔強(qiáng)????)
上面我們提到了,內(nèi)聯(lián)是會將代碼移動到調(diào)用處,降低 一層棧幀,但這個性能提升真的大嗎?
再仔細(xì)想想,移動到調(diào)用處,移動到調(diào)用處。這是什么概念呢?
假設(shè)我們某個方法里代碼只有兩行(我想不會有人會某個方法只有一行吧??),這個方法又被好幾處調(diào)用,內(nèi)聯(lián)是提高了調(diào)用性能,畢竟節(jié)省了一次棧幀,再加上方法行數(shù)少(暫時拋棄虛擬機(jī)優(yōu)化這個底層條件)。
但如果方法里代碼有幾十行?每次調(diào)用都會把代碼內(nèi)聯(lián)過來,那調(diào)用處豈不??,帶來的包大小影響某種程度上要比內(nèi)聯(lián)成本更高????!
如下圖所示,我們對上述示例做一個論證:
Jvm: 我謝謝你。
推薦示例
我們在文章最開始提到了,Kotlin inline
,一般建議用于 高階函數(shù)(lambda) 中。為什么呢?
如下示例:
轉(zhuǎn)成字節(jié)碼后,可以發(fā)現(xiàn),tryKtx()
被創(chuàng)建為了一個匿名內(nèi)部類 (Simple$test|1)
。每次調(diào)用時,相當(dāng)于需要創(chuàng)建匿名類的實(shí)例對象,從而導(dǎo)致二次調(diào)用的性能損耗。
那如果我們給其增加 inline
呢???,反編譯后相應(yīng)的 java代碼 如下:
具體對比圖如上所示,不難發(fā)現(xiàn),我們的調(diào)用處已經(jīng)被替換為原方法,相應(yīng)的 lambda
也被消除了,從而顯著減少了性能損耗。
小結(jié)
如果查看官方庫相應(yīng)的代碼,如下所示,比如 with
:
public inline fun <T, R> with(receiver: T, block: T.() -> R): R { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } return receiver.block() }
不難發(fā)現(xiàn),inline
的大多數(shù)場景僅且在 高階函數(shù) 并且 方法行數(shù)較短 時適用。因?yàn)閷τ谄胀ǚ椒?,jvm本身對其就會進(jìn)行優(yōu)化,所以 inline
在普通方法上的的意義幾乎聊勝于無。
總結(jié)
- 因?yàn)閮?nèi)聯(lián)函數(shù)會將方法函數(shù)移動到調(diào)用處,會增加調(diào)用處的代碼量,所以對于較長的方法應(yīng)該避免使用;
- 內(nèi)聯(lián)函數(shù)應(yīng)該用于使用了 高階函數(shù)(lambda) 的方法,而不是普通方法。
以上就是Kotlin內(nèi)存陷阱inline使用技巧示例詳解的詳細(xì)內(nèi)容,更多關(guān)于Kotlin內(nèi)存陷阱inline使用的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
logback-spring.xml的配置及示例詳解(直接復(fù)制粘貼可用)
在使用logback作為日志框架時,可以創(chuàng)建一個名為logback-spring.xml的配置文件來自定義日志輸出的格式和方式,下面這篇文章主要給大家介紹了關(guān)于logback-spring.xml的配置及示例詳解的相關(guān)資料,文中的代碼直接復(fù)制粘貼可用,需要的朋友可以參考下2024-01-01SpringMVC數(shù)據(jù)輸出相關(guān)知識總結(jié)
今天帶大家學(xué)習(xí)SpringMVC的相關(guān)知識,文中對SpringMVC數(shù)據(jù)輸出作了非常詳細(xì)的代碼示例,對正在學(xué)習(xí)的小伙伴們很有幫助,需要的朋友可以參考下2021-06-06RabbitMQ中Confirm消息確認(rèn)機(jī)制保障生產(chǎn)端消息的可靠性詳解
這篇文章主要介紹了RabbitMQ中Confirm消息確認(rèn)機(jī)制保障生產(chǎn)端消息的可靠性詳解,生產(chǎn)者將數(shù)據(jù)發(fā)送到 RabbitMQ 的時候,可能數(shù)據(jù)就在半路給搞丟了,因?yàn)榫W(wǎng)絡(luò)問題啥的,都有可能,需要的朋友可以參考下2023-12-12Java+Selenium實(shí)現(xiàn)控制瀏覽器的啟動選項Options
這篇文章主要為大家詳細(xì)介紹了如何使用java代碼利用selenium控制瀏覽器的啟動選項Options的代碼操作,文中的示例代碼講解詳細(xì),感興趣的可以了解一下2023-01-01