【安卓逆向】Java中的魔術(shù)類

簡(jiǎn)單談一談Java中的Unsafe類

Unsafe類是啥?

Java最初被設(shè)計(jì)為一種安全的受控環(huán)境。盡管如此筋栋,Java HotSpot還是包含了一個(gè)“后門(mén)”敏簿,提供了一些可以直接操控內(nèi)存和線程的低層次操作净薛。這個(gè)后門(mén)類——sun.misc.Unsafe——被JDK廣泛用于自己的包中擂送,如java.nio和java.util.concurrent弄贿。但是絲毫不建議在生產(chǎn)環(huán)境中使用這個(gè)后門(mén)液斜。因?yàn)檫@個(gè)API十分不安全求类、不輕便奔垦、而且不穩(wěn)定。這個(gè)不安全的類提供了一個(gè)觀察HotSpot JVM內(nèi)部結(jié)構(gòu)并且可以對(duì)其進(jìn)行修改仑嗅。有時(shí)它可以被用來(lái)在不適用C++調(diào)試的情況下學(xué)習(xí)虛擬機(jī)內(nèi)部結(jié)構(gòu)宴倍,有時(shí)也可以被拿來(lái)做性能監(jiān)控和開(kāi)發(fā)工具。

引言

Java當(dāng)中神奇的Unsafe類仓技,(可以稱作魔術(shù)鸵贬,哈哈)在這里跟大家分享一下。


Unsafe類是在sun.misc包下脖捻,不屬于Java標(biāo)準(zhǔn)阔逼。但是很多Java的基礎(chǔ)類庫(kù),包括一些被廣泛使用的高性能開(kāi)發(fā)庫(kù)都是基于Unsafe類開(kāi)發(fā)的地沮,比如Netty嗜浮、Cassandra、Hadoop摩疑、Kafka等危融。Unsafe類在提升Java運(yùn)行效率,增強(qiáng)Java語(yǔ)言底層操作能力方面起了很大的作用雷袋。


Unsafe類使Java擁有了像C語(yǔ)言的指針一樣操作內(nèi)存空間的能力吉殃,同時(shí)也帶來(lái)了指針的問(wèn)題。過(guò)度的使用Unsafe類會(huì)使得出錯(cuò)的幾率變大楷怒,因此Java官方并不建議使用的蛋勺,官方文檔也幾乎沒(méi)有。Oracle正在計(jì)劃從Java 9中去掉Unsafe類鸠删,如果真是如此影響就太大了抱完。

通常我們最好也不要使用Unsafe類,除非有明確的目的刃泡,并且也要對(duì)它有深入的了解才行巧娱。要想使用Unsafe類需要用一些比較tricky的辦法。Unsafe類使用了單例模式捅僵,需要通過(guò)一個(gè)靜態(tài)方法getUnsafe()來(lái)獲取家卖。但Unsafe類做了限制,如果是普通的調(diào)用的話庙楚,它會(huì)拋出一個(gè)SecurityException異常;只有由主類加載器加載的類才能調(diào)用這個(gè)方法趴樱。其源碼如下:

1

2

3

4

5

6

7

8

publicstaticUnsafe getUnsafe() {

?Class var0 = Reflection.getCallerClass();

?if(!VM.isSystemDomainLoader(var0.getClassLoader())) {

??thrownewSecurityException("Unsafe");

?} else{

??returntheUnsafe;

?}

}


網(wǎng)上也有一些辦法來(lái)用主類加載器加載用戶代碼馒闷,比如設(shè)置bootclasspath參數(shù)酪捡。但更簡(jiǎn)單方法是利用Java反射,方法如下:

1

2

3

Field f = Unsafe.class.getDeclaredField("theUnsafe");

f.setAccessible(true);

Unsafe unsafe = (Unsafe) f.get(null);

獲取到Unsafe實(shí)例之后纳账,我們就可以為所欲為了逛薇。Unsafe類提供了以下這些功能:

一、內(nèi)存管理疏虫。包括分配內(nèi)存永罚、釋放內(nèi)存等。

該部分包括了allocateMemory(分配內(nèi)存)卧秘、reallocateMemory(重新分配內(nèi)存)呢袱、copyMemory(拷貝內(nèi)存)、freeMemory(釋放內(nèi)存 )翅敌、getAddress(獲取內(nèi)存地址)羞福、addressSize、pageSize蚯涮、getInt(獲取內(nèi)存地址指向的整數(shù))治专、getIntVolatile(獲取內(nèi)存地址指向的整數(shù),并支持volatile語(yǔ)義)遭顶、putInt(將整數(shù)寫(xiě)入指定內(nèi)存地址)张峰、putIntVolatile(將整數(shù)寫(xiě)入指定內(nèi)存地址,并支持volatile語(yǔ)義)棒旗、putOrderedInt(將整數(shù)寫(xiě)入指定內(nèi)存地址喘批、有序或者有延遲的方法)等方法。getXXX和putXXX包含了各種基本類型的操作嗦哆。

利用copyMemory方法谤祖,我們可以實(shí)現(xiàn)一個(gè)通用的對(duì)象拷貝方法,無(wú)需再對(duì)每一個(gè)對(duì)象都實(shí)現(xiàn)clone方法老速,當(dāng)然這通用的方法只能做到對(duì)象淺拷貝粥喜。

二、非常規(guī)的對(duì)象實(shí)例化橘券。

allocateInstance()方法提供了另一種創(chuàng)建實(shí)例的途徑额湘。通常我們可以用new或者反射來(lái)實(shí)例化對(duì)象,使用allocateInstance()方法可以直接生成對(duì)象實(shí)例旁舰,且無(wú)需調(diào)用構(gòu)造方法和其它初始化方法锋华。

這在對(duì)象反序列化的時(shí)候會(huì)很有用,能夠重建和設(shè)置final字段箭窜,而不需要調(diào)用構(gòu)造方法毯焕。

三、操作類、對(duì)象纳猫、變量婆咸。

這部分包括了staticFieldOffset(靜態(tài)域偏移)、defineClass(定義類)芜辕、defineAnonymousClass(定義匿名類)尚骄、ensureClassInitialized(確保類初始化)、objectFieldOffset(對(duì)象域偏移)等方法侵续。

通過(guò)這些方法我們可以獲取對(duì)象的指針倔丈,通過(guò)對(duì)指針進(jìn)行偏移,我們不僅可以直接修改指針指向的數(shù)據(jù)(即使它們是私有的)状蜗,甚至可以找到JVM已經(jīng)認(rèn)定為垃圾需五、可以進(jìn)行回收的對(duì)象。

四诗舰、數(shù)組操作警儒。

這部分包括了arrayBaseOffset(獲取數(shù)組第一個(gè)元素的偏移地址)、arrayIndexScale(獲取數(shù)組中元素的增量地址)等方法眶根。arrayBaseOffset與arrayIndexScale配合起來(lái)使用蜀铲,就可以定位數(shù)組中每個(gè)元素在內(nèi)存中的位置。

由于Java的數(shù)組最大值為Integer.MAX_VALUE属百,使用Unsafe類的內(nèi)存分配方法可以實(shí)現(xiàn)超大數(shù)組记劝。實(shí)際上這樣的數(shù)據(jù)就可以認(rèn)為是C數(shù)組,因此需要注意在合適的時(shí)間釋放內(nèi)存族扰。

五厌丑、多線程同步。包括鎖機(jī)制渔呵、CAS操作等怒竿。

這部分包括了monitorEnter、tryMonitorEnter扩氢、monitorExit耕驰、compareAndSwapInt、compareAndSwap等方法录豺。

其中monitorEnter朦肘、tryMonitorEnter、monitorExit已經(jīng)被標(biāo)記為deprecated双饥,不建議使用媒抠。

Unsafe類的CAS操作可能是用的最多的,它為Java的鎖機(jī)制提供了一種新的解決辦法咏花,比如AtomicInteger等類都是通過(guò)該方法來(lái)實(shí)現(xiàn)的趴生。compareAndSwap方法是原子的,可以避免繁重的鎖機(jī)制,提高代碼效率冲秽。這是一種樂(lè)觀鎖舍咖,通常認(rèn)為在大部分情況下不出現(xiàn)競(jìng)態(tài)條件矩父,如果操作失敗锉桑,會(huì)不斷重試直到成功。

六窍株、掛起與恢復(fù)民轴。

這部分包括了park、unpark等方法球订。

將一個(gè)線程進(jìn)行掛起是通過(guò)park方法實(shí)現(xiàn)的后裸,調(diào)用 park后,線程將一直阻塞直到超時(shí)或者中斷等條件出現(xiàn)冒滩。unpark可以終止一個(gè)掛起的線程微驶,使其恢復(fù)正常。整個(gè)并發(fā)框架中對(duì)線程的掛起操作被封裝在 LockSupport類中开睡,LockSupport類中有各種版本pack方法因苹,但最終都調(diào)用了Unsafe.park()方法。

七篇恒、內(nèi)存屏障扶檐。

這部分包括了loadFence、storeFence胁艰、fullFence等方法款筑。這是在Java 8新引入的,用于定義內(nèi)存屏障腾么,避免代碼重排序奈梳。

loadFence() 表示該方法之前的所有l(wèi)oad操作在內(nèi)存屏障之前完成。同理storeFence()表示該方法之前的所有store操作在內(nèi)存屏障之前完成解虱。fullFence()表示該方法之前的所有l(wèi)oad攘须、store操作在內(nèi)存屏障之前完成。

總結(jié)

以上就是這篇文章的全部?jī)?nèi)容了饭寺,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值阻课,如果有疑問(wèn)大家可以留言交流。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末艰匙,一起剝皮案震驚了整個(gè)濱河市限煞,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌员凝,老刑警劉巖署驻,帶你破解...
    沈念sama閱讀 211,743評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡旺上,警方通過(guò)查閱死者的電腦和手機(jī)瓶蚂,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,296評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)宣吱,“玉大人窃这,你說(shuō)我怎么就攤上這事≌骱颍” “怎么了杭攻?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,285評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)疤坝。 經(jīng)常有香客問(wèn)我兆解,道長(zhǎng),這世上最難降的妖魔是什么跑揉? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,485評(píng)論 1 283
  • 正文 為了忘掉前任锅睛,我火速辦了婚禮,結(jié)果婚禮上历谍,老公的妹妹穿的比我還像新娘现拒。我一直安慰自己,他們只是感情好扮饶,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,581評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布具练。 她就那樣靜靜地躺著,像睡著了一般甜无。 火紅的嫁衣襯著肌膚如雪扛点。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,821評(píng)論 1 290
  • 那天岂丘,我揣著相機(jī)與錄音陵究,去河邊找鬼。 笑死奥帘,一個(gè)胖子當(dāng)著我的面吹牛铜邮,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播寨蹋,決...
    沈念sama閱讀 38,960評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼松蒜,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了已旧?” 一聲冷哼從身側(cè)響起秸苗,我...
    開(kāi)封第一講書(shū)人閱讀 37,719評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎运褪,沒(méi)想到半個(gè)月后惊楼,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體玖瘸,經(jīng)...
    沈念sama閱讀 44,186評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,516評(píng)論 2 327
  • 正文 我和宋清朗相戀三年檀咙,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了雅倒。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,650評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡弧可,死狀恐怖蔑匣,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情侣诺,我是刑警寧澤殖演,帶...
    沈念sama閱讀 34,329評(píng)論 4 330
  • 正文 年R本政府宣布,位于F島的核電站年鸳,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏丸相。R本人自食惡果不足惜搔确,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,936評(píng)論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望灭忠。 院中可真熱鬧膳算,春花似錦、人聲如沸弛作。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,757評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)映琳。三九已至机隙,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間萨西,已是汗流浹背有鹿。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,991評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留谎脯,地道東北人葱跋。 一個(gè)月前我還...
    沈念sama閱讀 46,370評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像源梭,于是被迫代替她去往敵國(guó)和親娱俺。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,527評(píng)論 2 349

推薦閱讀更多精彩內(nèi)容