其實你不知道MultiDex到底有多坑

遭遇MultiDex

愉快地寫著Android代碼的總悟君往工程里引入了一個默默無聞的jar然后Run了一下杉适, 經(jīng)過漫長的等待AndroidStudio構建失敗了谎倔。

于是總悟君帶著疑惑查看錯誤信息。

看起來是:在試圖將 classes和jar塞進一個Dex文件的過程中產(chǎn)生了錯誤猿推。

早期的Dex文件保存所有classes的方法個數(shù)的范圍在0~65535之間片习。業(yè)務一直在增長,總悟君寫(copy)的代碼越來越長引入的庫越來越多蹬叭,超過這個范圍只是時間問題藕咏。

怎么解?秽五?太陽底下木有新鮮事孽查,淡定先google一發(fā),找找已經(jīng)踩過坑的小伙伴坦喘。

StackOverflow 的網(wǎng)友們對該問題表示情緒穩(wěn)定卦碾,談笑間拋出multiDex铺坞。

這是Android官網(wǎng)對當初的短視行為給出的補丁方案。文檔說洲胖,Dalvik Executable (DEX)文件的總方法數(shù)限制在65536以內(nèi)粹胯,其中包括Android framwork method沪悲, lib method (后來總悟君發(fā)現(xiàn)僅僅是Android 自己的框架的方法就已經(jīng)占用了1w多)术吗,還有你的 code method 骂蓖,所以請使用MultiDex。 對于5.0以下版本叉弦,請使用multidex support library (這個是我們的補丁包丐一!build tools 請升級到21)。而5.0及以上版本淹冰,由于ART模式的存在库车,app第一次安裝之后會進行一次預編譯(pre-compilation) ,如果這時候發(fā)現(xiàn)了classes(..N).dex文件的存在就會將他們最終合成為一個.oat的文件樱拴,嗯看起來很厲害的樣子柠衍。

同時Google建議review代碼的直接或者間接依賴,盡可能減少依賴庫晶乔,設置proguard參數(shù)進一步優(yōu)化去除無用的代碼珍坊。嗯,這兩個實施起來倒是很簡單正罢,但是治標不治本阵漏,躲得過初一躲不過十五。 在Google給出這個解決方案之前翻具,他們的開發(fā)人員先給了一個簡陋簡易版本的multiDex具體參看這里履怯。(懷疑后來的官方解決方案就有這家伙參與)。簡單地說就是:1.先把你的app 的class 拆分成主次兩個dex裆泳。2.你的程序運行起來后虑乖,自己把第二個dex給load進來×缆牵看就這么簡單!而且這就是個動態(tài)加載模塊的框架仅叫! 然而總悟君早已看穿Dalvik VM 這種動態(tài)加載dex 的能力歸根結底還是因為java 的classloader類加載機制帜篇。沿著這條道走,Android模塊動態(tài)化加載诫咱,包括dex級別和apk級別的動態(tài)化加載笙隙,各種玩法層出不窮。參見這里123456坎缭。

第一回合 天真的官方補丁方案

還是先解決打包問題竟痰,回頭再研究那些高深的動態(tài)化加載技術签钩。偷懶一下咯考慮到投入產(chǎn)出比,決定使用Google官方的multiDex解決坏快。(Google的補丁方案啊铅檩,不會再有坑了吧?后面才發(fā)現(xiàn)還是太天真) 該方案有兩步:

1.修改gradle腳本來產(chǎn)生多dex莽鸿。

2.修改manifest 使用MulitDexApplication昧旨。

步驟1.在gradle腳本里寫上:

步驟2. manifest聲明修改

如果有自己的Application,繼承MulitDexApplication祥得。如果當前代碼已經(jīng)繼承自其它Application沒辦法修改那也行兔沃,就重寫 Application的attachBaseContext()這個方法。

run一下级及,可以了乒疏!但是dex過程好像變慢了。饮焦。怕吴。

文檔還寫明了multiDex support lib 的局限。瞄一下是什么:

1.在應用安裝到手機上的時候dex文件的安裝是復雜的(complex)有可能會因為第二個dex文件太大導致ANR追驴。請用proguard優(yōu)化你的代碼械哟。呵呵

2.使用了mulitDex的App有可能在4.0(api level 14)以前的機器上無法啟動殿雪,因為Dalvik linearAlloc bug(Issue22586) 暇咆。請多多測試自祈多福索抓。用proguard優(yōu)化你的代碼將減少該bug幾率。呵呵

3.使用了mulitDex的App在runtime期間有可能因為Dalvik linearAlloc limit (Issue78035) Crash昆箕。該內(nèi)存分配限制在 4.0版本被增大,但是5.0以下的機器上的Apps依然會存在這個限制券勺。

4.主dex被dalvik虛擬機執(zhí)行時候绪钥,哪些類必須在主dex文件里面這個問題比較復雜。build tools 可以搞定這個問題关炼。但是如果你代碼存在反射和native的調(diào)用也不保證100%正確程腹。呵呵

感覺這就是個坑啊。補丁方案又引入一些問題儒拂。但是插件化方案要求對現(xiàn)有代碼有比較大的改動寸潦,代價太大,而且動態(tài)化加載框架意味著維護成本更高社痛,會有更多潛在bug见转。所以先測試,遇到有問題的版本再解決褥影。

第二回合 啥?dexopt failed咏雌?

呵呵凡怎,部分低端2.3機型(話說2.3版本的android機有高端機型么)安裝失斝=埂!INSTALL_FAILED_DEXOPT统倒。這個就是前面說的Issue22586問題寨典。

apk是一個zip壓縮包,dalvik每次加載apk都要從中解壓出class.dex文件房匆,加載過程還涉及到dex的classes需要的雜七雜八的依賴庫的加載耸成,真耗時間。于是Android決定優(yōu)化一下這個問題浴鸿,在app安裝到手機之后井氢,系統(tǒng)運行dexopt程序?qū)ex進行優(yōu)化,將dex的依賴庫文件和一些輔助數(shù)據(jù)打包成odex文件岳链。存放在cache/dalvik_cache目錄下花竞。保存格式為apk路徑 @ apk名 @ classes.dex。這樣以空間換時間大大縮短讀取/加載dex文件的過程掸哑。

那剛才那個bug是啥問題呢约急,原來dexopt程序的dalvik分配一塊內(nèi)存來統(tǒng)計你的app的dex里面的classes的信息,由于classes太多方法太多超過這個linearAlloc 的限制 苗分。那減小dex的大小就可以咯厌蔽。

gradle腳本如下:

--set-max-idx-number=用于控制每一個dex的最大方法個數(shù),寫小一點可以產(chǎn)生好幾個dex摔癣。 踩過更多坑的FB的工程師表示這個linearAlloc的限制不僅僅在安裝時候的dexopt程序里7奴饮,還在你的app的dalvik rumtime里。(很顯然啊dvk vm的宿主進程fork自于同一個母體肮┨睢)拐云。為了表示對這個坑的不滿以及對Google的產(chǎn)品表示遺憾,F(xiàn)B工程師Read The Fucking Source Code找到了一個hack方案近她。這個linearAlloc的size定義在c層而且是一個全局變量叉瘩,他們通過對結構體的size的計算成功覆蓋了該值的內(nèi)容,這里要特別感謝C語言的指針和內(nèi)存的設計粘捎。C的世界里薇缅,You Are The King of This World。當然實際情況是大部分用戶用這把利刃割傷了自己攒磨。泳桦。。別問總悟君誰是世界上最好的語言娩缰。灸撰。。

為FB的工程師的機智和務實精神點贊!然而總悟君不愿意花那么多精力實現(xiàn)FB的hack方法浮毯。(dvk虛擬機c層代碼在2.x 4.x 版本里有變更完疫,找到那個內(nèi)存地址太難,未必搞得定罢丁)我們有偷懶的解決方案壳鹤,為了避免2.3機型runtime 的linearAlloclimit ,最好保持每一個dex體積<4M ,剛才的的value<=48000

好了 現(xiàn)在2.3的機器可以安裝run起來了!

第三回合 ANR的意思就是Application Not Responding

問題又來了饰迹!這次不僅僅是2.3 的機型芳誓!還有一些中檔配置的4.x系統(tǒng)的機型。問題現(xiàn)象是:第一次安裝后啊鸭,點擊圖標锹淌,1s,2s莉掂,3s... 程序沒有任何反應就好像你沒點圖標一樣葛圃。

5s過去。憎妙。库正。程序ANR!

其實不僅僅總悟君的App存在這個問題,其他很多App也存在首次安裝運行后幾秒都無任何響應的現(xiàn)象或者最后ANR了厘唾。唯一的例外是美團App褥符,點擊圖標立馬就出現(xiàn)界面。唉要不就算啦抚垃?反正就一次喷楣。。鹤树。不行铣焊,這可是產(chǎn)品給用戶的第一印象啊太重要了,而且美團搞得定就說明這問題有解決方案罕伯。

ANR了是不是局限1描述的現(xiàn)象曲伊??不過也不重要...因為Google只是告訴你說第二個dex太大了導致的追他。并沒有進一步解釋根本原因坟募。怎么辦?Google一發(fā)邑狸?搜索點擊圖標 然后ANR懈糯?怎么可能有解決方案嘛。ANR就意味著UI線程被阻塞了单雾,老老實實查看log吧赚哗。

adb logcat -v time > log.txt

于是發(fā)現(xiàn) 是 install dex + dexopt 時間太長她紫!

梳理一下流程:

安裝完app點擊圖標之后,系統(tǒng)木有發(fā)現(xiàn)對應的process屿储,于是從該apk抽取classes.dex(主dex) 加載犁苏,觸發(fā) 一次dexopt。

App 的laucherActivity準備啟動 扩所,觸發(fā)Application啟動,

Application的 onattach()方法調(diào)用朴乖,這時候MultiDex.install()調(diào)用祖屏,classes2.dex 被install,再次觸發(fā)dexopt买羞。

然后Applicaition onCreate()執(zhí)行袁勺。

然后 launcher Activity真的起來了。

這些必須在5s內(nèi)完成不然就ANR給你看畜普!

有點棘手期丰。首先主dex是無論如何都繞不過加載和dexopt的。如果主dex比較小的話可以節(jié)省時間吃挑。主dex小就意味著后面的dex大啊钝荡,MultiDex.install()是在主線程里做的,總時間又沒有實質(zhì)性改變舶衬。install() 能不能放到線程里做安和ā?貌似不行逛犹。端辱。。如果異步化虽画,什么時候install完成都不知道舞蔽。這時候如果進程需要seconday.dex里的classes信息不就悲劇码撰?主dex越小這個錯誤幾率就越大渗柿。要悲劇啊總悟君。

淡定灸拍,這次Google搜索MultiDex.install 做祝。于是總悟君發(fā)現(xiàn)了美團多dex拆包方案。 讀完之后感覺看到勝利曙光鸡岗。美團的主要思路是:精簡主dex+異步加載secondary.dex 混槐。對異步化執(zhí)行速度的不確定性,他們的解決方案是重寫Instrumentation execStartActivity 方法轩性,hook跳轉(zhuǎn)Activity的總?cè)肟谧雠袛嗌牵绻斍皊econdary.dex 還沒有加載完成,就彈一個loading Activity等待加載完成,如果已經(jīng)加載完成那最好不過了悯嗓。不錯件舵,RTFSC果然是王道。 可以試一試脯厨。

但是有幾個問題需要解決:

1.分析主dex需要的classes這個腳本比較難寫铅祸。。合武。Google文檔說過這個問題比較復雜临梗, 而且buildTools 不是已經(jīng)幫我們搞定了嗎?去瞄一下主dex的大屑谔:8M 以及secondary.dex 3M 盟庞。 它是如何工作的?文檔說dx的時候汤善,先依據(jù)manifest里注冊的組件生成一個 main-list什猖,然后把這list里的classes所依賴的classes找出來,把他們打成classes.dex就是主dex红淡。剩下的classes都放clsses2.dex(如果使用參數(shù)限制dex大小的話可能會有classe3.ex 等等) 不狮。主dex至少含有main-list 的classes + 直接依賴classes ,使用mini-main-list參數(shù)可以僅僅包含剛才說的classes在旱。

關于寫分析腳本的思路是:直接使用mini-main-list參數(shù)獲取build目錄下的main-list文件荤傲,這樣manifest聲明的類和他們的直接依賴類搞定的了,那后者的直接依賴類怎么解颈渊?這些在dvk runtime也是必須的classes遂黍。一個思路是解析class文件獲得該class的依賴類。還一個思路是自己使用Dexclassloader 加載dex俊嗽,然后hook getClass()方法雾家,調(diào)用一次就記錄一個。都挺折騰的绍豁。

2.由于歷史原因芯咧,總悟君在維護的App的manifest注冊的組件的那些類,承載業(yè)務太多竹揍,依賴很多三方jar敬飒,導致直接依賴類非常多,而且短時間內(nèi)無法梳理精簡芬位,沒辦法mini化主dex无拗。

3.Application的啟動入口太多。Appication初始化未必是由launcher Activity的啟動觸發(fā)昧碉,還有可能是因為Service 英染,Receiver 揽惹,ContentProvider 的啟動。 靠攔截重寫Instrumentation execStartActivity 解決不了問題四康。要為 Service 搪搏,Receiver ,ContentProvider 分別寫基類闪金,然后在oncreate()里判斷是否要異步加載secondary.dex疯溺。如果需要,彈出Loading Acitvity哎垦?用戶看到這個會感覺比較怪異喝检。

結合自身App的實際情況來看美團的拆包方案雖然很美好然但是不能照搬啊。果然不能愉快地回家看動漫了撼泛。

第四回合 換一種思路

考慮到剛才說的2,3原因澡谭,先不要急著動手寫分析腳本愿题。總悟君期望找到更好的方案蛙奖。問題到現(xiàn)在變成了:既希望在Application的attachContext()方法里同步加載secondary.dex潘酗,又不希望卡住UI線程。如果思路限制在線程異步化上雁仲,確實不可能實現(xiàn)仔夺。于是發(fā)現(xiàn)了微信開發(fā)團隊的這篇文章。該文章介紹了關于這一問題 FB/QQ/微信的解決方案攒砖。FB的解決思路特別贊缸兔,讓Launcher Activity在另外一個進程啟動!當然這個Launcher Activity就是用來load dex 的 吹艇,load完成就啟動Main Activity惰蜜。

微信這篇文章給出了一個非常重要的觀點:安裝完成之后第一次啟動時,是secondary.dex的dexopt花費了更多的時間受神。認識到這點非常重要抛猖,使得問題又轉(zhuǎn)化為:在不阻塞UI線程的前提下,完成dexopt鼻听,以后都不需要再次dexopt财著,所以可以在UI線程install dex 了!文章最后給了一個對FB方案的改進版撑碴。

仔細讀完感覺完全可行撑教。

1.對現(xiàn)有代碼改動量最小。

2.該方案不關注Application被哪個組件啟動醉拓。Activity 驮履,Service 鱼辙,Receiver ,ContentProvider 都滿足玫镐。(有個問題要說明:如細心網(wǎng)友指出的那樣倒戏,新安裝還未啟動但是收到Receiver的場景下,會導致Load界面出現(xiàn)恐似。這個場景實際出現(xiàn)幾率比較少杜跷,且僅出現(xiàn)一次〗靡模可以接受葛闷。)

3.該方案不限制 Application ,Activity 双藕,Service 淑趾,Receiver ,ContentProvider 繼續(xù)新增業(yè)務忧陪。

于是總悟君實現(xiàn)了這篇文章最后介紹的改進版的方法扣泊,稍微有一點點擴充。

流程圖如下

上最終解決問題版的代碼嘶摊!

在Application里面(這里不要再繼承自MultiApplication了延蟹,我們要手動加載Dex):

importjava.util.Map;

importjava.util.jar.Attributes;

importjava.util.jar.JarFile;

importjava.util.jar.Manifest;

publicclassAppextendsApplication{

publicstaticfinalStringKEY_DEX2_SHA1="dex2-SHA1-Digest";

@Override

protectedvoidattachBaseContext(Contextbase){

super.attachBaseContext(base);

LogUtils.d("loadDex","App attachBaseContext ");

if(!quickStart()&&Build.VERSION.SDK_INT=5.0的系統(tǒng)默認對dex進行oat優(yōu)化

if(needWait(base)){

waitForDexopt(base);

}

MultiDex.install(this);

}else{

return;

}

}

@Override

publicvoidonCreate(){

super.onCreate();

if(quickStart()){

return;

}

...

}

publicbooleanquickStart(){

if(StringUtils.contains(getCurProcessName(this),":mini")){

LogUtils.d("loadDex",":mini start!");

returntrue;

}

returnfalse;

}

//neead wait for dexopt ?

privatebooleanneedWait(Contextcontext){

Stringflag=get2thDexSHA1(context);

LogUtils.d("loadDex","dex2-sha1 "+flag);

SharedPreferencessp=context.getSharedPreferences(

PackageUtil.getPackageInfo(context).versionName,MODE_MULTI_PROCESS);

StringsaveValue=sp.getString(KEY_DEX2_SHA1,"");

return!StringUtils.equals(flag,saveValue);

}

/**

* Get classes.dex file signature

* @param context

* @return

*/

privateStringget2thDexSHA1(Contextcontext){

ApplicationInfoai=context.getApplicationInfo();

Stringsource=ai.sourceDir;

try{

JarFilejar=newJarFile(source);

Manifestmf=jar.getManifest();

Mapmap=mf.getEntries();

Attributesa=map.get("classes2.dex");

returna.getValue("SHA1-Digest");

}catch(Exceptione){

e.printStackTrace();

}

returnnull;

}

// optDex finish

publicvoidinstallFinish(Contextcontext){

SharedPreferencessp=context.getSharedPreferences(

PackageUtil.getPackageInfo(context).versionName,MODE_MULTI_PROCESS);

sp.edit().putString(KEY_DEX2_SHA1,get2thDexSHA1(context)).commit();

}

publicstaticStringgetCurProcessName(Contextcontext){

try{

intpid=android.os.Process.myPid();

ActivityManagermActivityManager=(ActivityManager)context

.getSystemService(Context.ACTIVITY_SERVICE);

for(ActivityManager.RunningAppProcessInfoappProcess:mActivityManager

.getRunningAppProcesses()){

if(appProcess.pid==pid){

returnappProcess.processName;

}

}

}catch(Exceptione){

// ignore

}

returnnull;

}

publicvoidwaitForDexopt(Contextbase){

Intentintent=newIntent();

ComponentNamecomponentName=new

ComponentName("com.zongwu",LoadResActivity.class.getName());

intent.setComponent(componentName);

intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

base.startActivity(intent);

longstartWait=System.currentTimeMillis();

longwaitTime=10*1000;

if(Build.VERSION.SDK_INT

waitTime=20*1000;//實測發(fā)現(xiàn)某些場景下有些2.3版本有可能10s都不能完成optdex

}

while(needWait(base)){

try{

longnowWait=System.currentTimeMillis()-startWait;

LogUtils.d("loadDex","wait ms :"+nowWait);

if(nowWait>=waitTime){

return;

}

Thread.sleep(200);

}catch(InterruptedExceptione){

e.printStackTrace();

}

}

}

}

PackageUtil的方法

這里使用了classes(N).dex的方式保存了后面的dex而不是像微信目前的做法放到assest文件夾。前面有說到ART模式會將多個dex優(yōu)化合并成oat文件叶堆。如果放置在asset里面就沒有這個好處了阱飘。

Launcher Activity 依然是原來的代碼里的WelcomeActivity。

在Application啟動的時候會檢測dexopt是否已經(jīng)完成過虱颗,(檢測方式是查看sp文件是否有dex文件的SHA1-Digest記錄沥匈,這里要兩個進程讀取該sp,讀取模式是MODE_MULTI_PROCESS)。如果沒有就啟動LoadDexActivity(屬于:mini進程) 忘渔。否則就直接install dex 咐熙!對,直接install辨萍。通過日志發(fā)現(xiàn)棋恼,已經(jīng)dexopt的dex文件再次install的時候 只耗費幾十毫秒。

LoadDexActivity 的邏輯比較簡單锈玉,啟動AsyncTask 來install dex 這時候會觸發(fā)dexopt 爪飘。

Manifest.xml 里面

替換Activity默認的出現(xiàn)動畫 R.anim.null_anim 文件的定義:

微信開發(fā)團隊的這篇文章所說,application啟動了LoadDexActivity之后拉背,自身不再是前臺進程所以怎么hold 線程都不會ANR师崎。

系統(tǒng)何時會對apk進行dexopt總悟君其實并沒有十分明白。通過查看安裝運行的日志發(fā)現(xiàn)椅棺,安裝的時候packageManagerService會對classes.dex 進行dexopt 犁罩。在調(diào)用MultiDex.install()加載 secondary.dex的時候齐蔽,也會進行一次dexopt 。 這背后的流程到底是怎樣的床估?dexopt是如何在另外一個進程執(zhí)行的含滴?如果是另外一個進程執(zhí)行為何會阻塞主app的UI進程? 官方文檔并沒有詳細介紹這個丐巫,那就RTFSC一探究竟吧.

源代碼跟蹤比較長谈况,移步到這里看吧。

轉(zhuǎn)載于:總悟君,http://blog.zongwu233.com/the-touble-of-multidex/

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末递胧,一起剝皮案震驚了整個濱河市碑韵,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌缎脾,老刑警劉巖祝闻,帶你破解...
    沈念sama閱讀 216,544評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異遗菠,居然都是意外死亡联喘,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評論 3 392
  • 文/潘曉璐 我一進店門舷蒲,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人友多,你說我怎么就攤上這事牲平。” “怎么了域滥?”我有些...
    開封第一講書人閱讀 162,764評論 0 353
  • 文/不壞的土叔 我叫張陵纵柿,是天一觀的道長。 經(jīng)常有香客問我启绰,道長昂儒,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,193評論 1 292
  • 正文 為了忘掉前任委可,我火速辦了婚禮渊跋,結果婚禮上,老公的妹妹穿的比我還像新娘着倾。我一直安慰自己拾酝,他們只是感情好,可當我...
    茶點故事閱讀 67,216評論 6 388
  • 文/花漫 我一把揭開白布卡者。 她就那樣靜靜地躺著蒿囤,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上维苔,一...
    開封第一講書人閱讀 51,182評論 1 299
  • 那天贫堰,我揣著相機與錄音捷绒,去河邊找鬼虐秦。 笑死豹休,一個胖子當著我的面吹牛筛武,可吹牛的內(nèi)容都是我干的庸追。 我是一名探鬼主播湿痢,決...
    沈念sama閱讀 40,063評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼涝缝,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了譬重?” 一聲冷哼從身側(cè)響起拒逮,我...
    開封第一講書人閱讀 38,917評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎臀规,沒想到半個月后滩援,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,329評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡塔嬉,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,543評論 2 332
  • 正文 我和宋清朗相戀三年玩徊,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片谨究。...
    茶點故事閱讀 39,722評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡恩袱,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出胶哲,到底是詐尸還是另有隱情畔塔,我是刑警寧澤,帶...
    沈念sama閱讀 35,425評論 5 343
  • 正文 年R本政府宣布鸯屿,位于F島的核電站澈吨,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏寄摆。R本人自食惡果不足惜谅辣,卻給世界環(huán)境...
    茶點故事閱讀 41,019評論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望婶恼。 院中可真熱鬧桑阶,春花似錦、人聲如沸勾邦。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,671評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽检痰。三九已至包归,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間铅歼,已是汗流浹背公壤。 一陣腳步聲響...
    開封第一講書人閱讀 32,825評論 1 269
  • 我被黑心中介騙來泰國打工换可, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人厦幅。 一個月前我還...
    沈念sama閱讀 47,729評論 2 368
  • 正文 我出身青樓沾鳄,卻偏偏與公主長得像,于是被迫代替她去往敵國和親确憨。 傳聞我的和親對象是個殘疾皇子译荞,可洞房花燭夜當晚...
    茶點故事閱讀 44,614評論 2 353

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