java內(nèi)存垃圾回收

研究JVM一定逃不開一個(gè)話題,就是垃圾回收(Garbage Collection懒豹,GC)脸秽。很多面試的程序員也應(yīng)該是“深受其擾”记餐,今天我們就來(lái)聊一聊我對(duì)于它的理解片酝。

在開始學(xué)習(xí)GC之前你應(yīng)該知道一個(gè)詞:Stop-the-world。不管選擇哪種GC算法审轮,stop-the-world都是不可避免的断国。Stop-the-world意味著從應(yīng)用中停下來(lái)并進(jìn)入到GC執(zhí)行過(guò)程中去稳衬。一旦Stop-the-world發(fā)生薄疚,除了GC所需的線程外,其他線程都將停止工作板丽,中斷了的線程直到GC任務(wù)結(jié)束才繼續(xù)它們的任務(wù)埃碱。GC調(diào)優(yōu)通常就是為了改善stop-the-world的時(shí)間。

想要了解java的GC似炎,我總結(jié)的五個(gè)關(guān)鍵字是WHY羡藐、WHERE仆嗦、WHAT欧啤、HOW、WHEN冈在。只要從這幾個(gè)關(guān)鍵詞一步步解釋纫谅,基本上就能大概了解java的GC工作兰珍。

先來(lái)解釋下這五個(gè)關(guān)鍵字代表的意思并逐一分析:
\blacklozenge WHY:為什么要進(jìn)行垃圾回收
\blacklozenge WHERE:哪里的內(nèi)容需要回收
\blacklozenge WHAT:什么對(duì)象可回收
\blacklozenge HOW:如何進(jìn)行回收
\blacklozenge WHEN:什么時(shí)候回收

WHY:為什么要進(jìn)行垃圾回收

回答這個(gè)問(wèn)題,要想一想如果不進(jìn)行垃圾收集會(huì)發(fā)生什么唠摹。我們知道,一個(gè)服務(wù)器的內(nèi)存都是有限的盗温,而JVM在工作時(shí)占用的內(nèi)存更不是任意擴(kuò)展的找默。所以如果我們對(duì)JVM在運(yùn)行時(shí)產(chǎn)生的垃圾數(shù)據(jù)不進(jìn)行收集,必然會(huì)出現(xiàn)撐爆內(nèi)存的情況风钻,服務(wù)也就無(wú)法再繼續(xù)運(yùn)轉(zhuǎn)。而垃圾收集能自動(dòng)釋放內(nèi)存空間并分配給新的對(duì)象布朦,讓服務(wù)能夠健康的運(yùn)轉(zhuǎn)昼窗。

WHERE:哪里的內(nèi)容需要回收

通過(guò)之前的文章 http://www.reibang.com/p/dd4f195c6464 我們知道是趴,Java在內(nèi)存運(yùn)行時(shí)數(shù)據(jù)區(qū)域有虛擬機(jī)棧、本地方法棧澄惊、程序計(jì)數(shù)器唆途、堆富雅、方法區(qū)。其中虛擬機(jī)棧肛搬、本地方法棧没佑、程序計(jì)數(shù)器隨線程而生,隨線程而滅温赔;棧中的棧幀隨著方法的進(jìn)入和退出而有條不紊地執(zhí)行著出棧和入棧操作。每一個(gè)棧幀中分配多少內(nèi)存基本上是在類結(jié)構(gòu)確定下來(lái)時(shí)就已知的,因此這幾個(gè)區(qū)域的內(nèi)存分配和回收都具備確定性,所以不需要考慮回收医舆,而Java堆和方法區(qū)則不一樣惫东,一個(gè)接口中的多個(gè)實(shí)現(xiàn)類需要的內(nèi)存可能不一樣,一個(gè)方法中的多個(gè)分支需要的內(nèi)存也可能不一樣遥皂,我們只有在程序處于運(yùn)行期間時(shí)才能知道會(huì)創(chuàng)建哪些對(duì)象,這部分內(nèi)存的分配和回收都是動(dòng)態(tài)的震糖,垃圾收集器所關(guān)注的是這部分內(nèi)存颁井。

WHAT:什么對(duì)象可回收

引用計(jì)數(shù)算法(目前java不使用)

這個(gè)算法是這樣的:給每個(gè)對(duì)象分配一個(gè)計(jì)算器眉抬,當(dāng)有引用指向這個(gè)對(duì)象時(shí)威沫,計(jì)數(shù)器加1颈墅,當(dāng)指向該對(duì)象的引用失效時(shí)望伦,計(jì)數(shù)器減1饵撑。最后如果該對(duì)象的計(jì)算器為0時(shí)酪刀,java垃圾回收器會(huì)認(rèn)為該對(duì)象是可回收的漾唉。
引用計(jì)數(shù)器算法算是一種古老的java垃圾回收算法,效率較高概漱,貌似JDK1.2之前還是是用的這個(gè)算法丑慎。目前的JDK版本已經(jīng)廢棄掉這種算法了照弥,之所以廢棄應(yīng)該是和它無(wú)法解決兩個(gè)對(duì)象間循環(huán)引用的問(wèn)題片迅。
循環(huán)引用可以參考:https://blog.csdn.net/jiasike/article/details/51355729

可達(dá)性分析算法(目前java使用)
可達(dá)性分析算法.png

目前java是通過(guò)可達(dá)性分析來(lái)判定對(duì)象是否存活的畅厢。這個(gè)算法的基本思路就是通過(guò)一系列的名為“GC Roots”的對(duì)象作為起始點(diǎn)浦楣,從這些節(jié)點(diǎn)開始向下搜索,搜索所走過(guò)的路徑稱為引用鏈(Reference Chain)咪辱,當(dāng)一個(gè)對(duì)象到GC Roots沒(méi)有任何引用鏈相連時(shí)振劳,則證明此對(duì)象是不可用的。如上圖可見油狂,對(duì)象Object4历恐、Object5、Object6雖然互相有關(guān)聯(lián)专筷,但是它們到GC Roots是不可達(dá)的弱贼,所以它們會(huì)被判定為是可回收對(duì)象。
在Java語(yǔ)言中磷蛹,可作為GC Roots的對(duì)象包括下面幾種:

\blacksquare 虛擬機(jī)棧(棧幀中的本地變量表)中引用的對(duì)象吮旅。
\blacksquare 方法區(qū)中類靜態(tài)屬性引用的對(duì)象。
\blacksquare 方法區(qū)中常量引用的對(duì)象味咳。
\blacksquare 本地方法棧中JNI(Native方法)引用的對(duì)象庇勃。

再聊一聊引用

無(wú)論是通過(guò)引用算法判斷對(duì)象的引用數(shù)量,還是通過(guò)可達(dá)性分析算法判斷對(duì)象的引用鏈?zhǔn)欠窨蛇_(dá)槽驶,判斷對(duì)象是否存活都與引用有關(guān)责嚷。我們希望能描述這樣一類對(duì)象:當(dāng)內(nèi)存空間還足夠時(shí),則能保留在內(nèi)存之中掂铐;如果內(nèi)存空間在進(jìn)行垃圾收集后還是非常緊張再层,則可以拋棄這些對(duì)象。很多系統(tǒng)的緩存功能都符合這樣的應(yīng)用場(chǎng)景堡纬。JDK1.2之后,Java對(duì)引用的概念進(jìn)行了擴(kuò)充蒿秦,將引用分為強(qiáng)引用烤镐、軟引用、弱引用棍鳖、虛引用4種炮叶。

\blacksquare 強(qiáng)引用
強(qiáng)引用就是指在程序代碼之中普遍存在的,類似“Object obj=new Object()”這類的引用渡处,只要強(qiáng)引用還存在镜悉,垃圾收集器永遠(yuǎn)不會(huì)回收掉被引用的對(duì)象。
\blacksquare 軟引用(SoftReference類)
軟引用是用來(lái)描述一些還有用但并非必需的對(duì)象医瘫。對(duì)于軟引用關(guān)聯(lián)著的對(duì)象侣肄,在系統(tǒng)將要發(fā)生內(nèi)存溢出異常之前,將會(huì)把這些對(duì)象列進(jìn)回收范圍之中進(jìn)行第二次回收醇份。如果這次回收還沒(méi)有足夠的內(nèi)存稼锅,才會(huì)拋出內(nèi)存溢出異常吼具。
\blacksquare 弱引用(WeakReference類)
弱引用也是用來(lái)描述非必需對(duì)象的,但是它的強(qiáng)度比軟引用更弱一些矩距,被弱引用關(guān)聯(lián)的對(duì)象只能生存到下一次垃圾收集發(fā)生之前拗盒。當(dāng)垃圾收集器工作時(shí),無(wú)論當(dāng)前內(nèi)存是否足夠锥债,都會(huì)回收掉只被弱引用關(guān)聯(lián)的對(duì)象陡蝇。
\blacksquare 虛引用(PhantomReference類)
虛引用也稱為幽靈引用或者幻影引用,它是最弱的一種引用關(guān)系哮肚。一個(gè)對(duì)象是否有虛引
用的存在登夫,完全不會(huì)對(duì)其生存時(shí)間構(gòu)成影響,也無(wú)法通過(guò)虛引用來(lái)取得一個(gè)對(duì)象實(shí)例绽左。為一個(gè)對(duì)象設(shè)置虛引用關(guān)聯(lián)的唯一目的就是能在這個(gè)對(duì)象被收集器回收時(shí)收到一個(gè)系統(tǒng)通知悼嫉。

回收方法區(qū)

方法區(qū)的垃圾收集主要回收兩部分內(nèi)容:廢棄常量和無(wú)用的類。

\gg 回收廢棄常量與回收J(rèn)ava堆中的對(duì)象非常類似拼窥。以常量池中字面量的回收為例戏蔑,假如一個(gè)字符串“abc”已經(jīng)進(jìn)入了常量池中,但是當(dāng)前系統(tǒng)沒(méi)有任何一個(gè)String對(duì)象是叫做“abc”的鲁纠,換句話說(shuō)总棵,就是沒(méi)有任何String對(duì)象引用常量池中的“abc”常量,也沒(méi)有其他地方引用了這個(gè)字面量改含,如果這時(shí)發(fā)生內(nèi)存回收情龄,而且必要的話,這個(gè)“abc”常量就會(huì)被系統(tǒng)清理出常量池捍壤。常量池中的其他類(接口)骤视、方法、字段的符號(hào)引用也與此類似鹃觉。

\gg 判定一個(gè)類是否是“無(wú)用的類”的條件有三個(gè):
\blacksquare 類所有的實(shí)例都已經(jīng)被回收专酗,也就是Java堆中不存在該類的任何實(shí)例。
\blacksquare 加載該類的ClassLoader已經(jīng)被回收盗扇。
\blacksquare 該類對(duì)應(yīng)的java.lang.Class對(duì)象沒(méi)有在任何地方被引用祷肯,無(wú)法在任何地方通過(guò)反射訪問(wèn)該類的方法。
虛擬機(jī)可以對(duì)滿足上述3個(gè)條件的無(wú)用類進(jìn)行回收疗隶,這里說(shuō)的僅僅是“可以”佑笋,而并不是和對(duì)象一樣,不使用了就必然會(huì)回收斑鼻。這個(gè)要根據(jù)不同廠商的虛擬機(jī)提供的參數(shù)而定(如HotSpot虛擬機(jī)提供了-Xnoclassgc參數(shù)進(jìn)行控制)蒋纬,這里就不多說(shuō)了。

HOW:如何進(jìn)行回收

這里就要聊一下垃圾收集算法。

標(biāo)記 - 清除算法

如同它的名字一樣颠锉,算法分為“標(biāo)記”和“清除”兩個(gè)階段:首先標(biāo)記出所有需要回收的對(duì)象法牲,在標(biāo)記完成后統(tǒng)一回收所有被標(biāo)記的對(duì)象。它的主要不足有兩個(gè):

  1. 效率問(wèn)題琼掠,標(biāo)記和清除兩個(gè)過(guò)程的效率都不高拒垃;
  2. 空間問(wèn)題,標(biāo)記清除之后會(huì)產(chǎn)生大量不連續(xù)的內(nèi)存碎片瓷蛙,空間碎片太多可能會(huì)導(dǎo)致以后在程序運(yùn)行過(guò)程中需要分配較大對(duì)象時(shí)悼瓮,無(wú)法找到足夠的連續(xù)內(nèi)存而不得不提前觸發(fā)另一次垃圾收集動(dòng)作。

標(biāo)記—清除算法的執(zhí)行過(guò)程如下圖所示:


image.png
復(fù)制算法

為了解決效率問(wèn)題艰猬,一種稱為“復(fù)制”(Copying)的收集算法出現(xiàn)了横堡,它將可用內(nèi)存按容量劃分為大小相等的兩塊,每次只使用其中的一塊冠桃。當(dāng)這一塊的內(nèi)存用完了命贴,就將還存活著的對(duì)象復(fù)制到另外一塊上面,然后再把已使用過(guò)的內(nèi)存空間一次清理掉食听。這樣使得每次都是對(duì)整個(gè)半?yún)^(qū)進(jìn)行內(nèi)存回收胸蛛,內(nèi)存分配時(shí)也就不用考慮內(nèi)存碎片等復(fù)雜情況,只要移動(dòng)堆頂指針樱报,按順序分配內(nèi)存即可葬项,實(shí)現(xiàn)簡(jiǎn)單,運(yùn)行高效迹蛤。 相對(duì)于下面“標(biāo)記-整理”策略需要多次遍歷堆進(jìn)行回收民珍,“復(fù)制式回收”只需要遍歷一次堆,同時(shí)也清理了”內(nèi)存碎片“盗飒,并保證了對(duì)象在堆中的相對(duì)順序(提高了程序的空間局部性)嚷量。但是它有個(gè)致命的缺點(diǎn)是堆的可利用空間只有一半。復(fù)制算法的執(zhí)行過(guò)程如下圖所示:


image.png

現(xiàn)在的商業(yè)虛擬機(jī)都采用這種收集算法來(lái)回收新生代逆趣,IBM公司的專門研究表明津肛,新生代中的對(duì)象98%是“朝生夕死”的,所以并不需要按照1:1的比例來(lái)劃分內(nèi)存空間汗贫,而是將內(nèi)存分為一塊較大的Eden空間和兩塊較小的Survivor空間,每次使用Eden和其中一塊Survivor秸脱。當(dāng)回收時(shí)落包,將Eden和Survivor中還存活著的對(duì)象一次性地復(fù)制到另外一塊Survivor空間上,最后清理掉Eden和剛才用過(guò)的Survivor空間摊唇。HotSpot虛擬機(jī)默認(rèn)Eden和Survivor的大小比例是8:1咐蝇,也就是每次新生代中可用內(nèi)存空間為整個(gè)新生代容量的90%(80%+10%),只有10%的內(nèi)存會(huì)被“浪費(fèi)”巷查。當(dāng)然有序,98%的對(duì)象可回收只是一般場(chǎng)景下的數(shù)據(jù)抹腿,我們沒(méi)有辦法保證每次回收都只有不多于10%的對(duì)象存活,當(dāng)Survivor空間不夠用時(shí)旭寿,需要依賴其他內(nèi)存(這里指老年代)進(jìn)行分配擔(dān)保(Handle Promotion - 如果另外一塊Survivor空間沒(méi)有足夠空間存放上一次新生代收集下來(lái)的存活對(duì)象時(shí)警绩,這些對(duì)象將直接進(jìn)入老年代)。


新生代的minor GC

對(duì)象能夠進(jìn)入到老年代的途徑:

  1. 空間分配擔(dān)保:通過(guò)上面提到的分配擔(dān)保方式盅称。
  2. 長(zhǎng)期存活對(duì)象:一般情況下肩祥,新創(chuàng)建的對(duì)象都會(huì)被分配到Eden區(qū)(一些大對(duì)象特殊處理),這些對(duì)象經(jīng)過(guò)它自己的第一次Minor GC后缩膝,如果仍然存活混狠,并且能被Survivor區(qū)容納,則將會(huì)被移到Survivor(to)區(qū)疾层,并且將年齡設(shè)置為2将饺。對(duì)象在Survivor區(qū)中每熬過(guò)一次Minor GC,年齡就會(huì)增加1歲痛黎,當(dāng)它的年齡增加到一定程度(默認(rèn)為15歲)時(shí)予弧,就會(huì)被移動(dòng)到老年代中。 可通過(guò)虛擬機(jī)提供的 -XX:MaxTenuringThreshold參數(shù)進(jìn)行配置移動(dòng)年齡闕值舅逸。
  3. 大對(duì)象:需要大量連續(xù)內(nèi)從空間的java對(duì)象直接進(jìn)入老年代桌肴,如很長(zhǎng)的字符串以及數(shù)組×鹄可通過(guò)虛擬機(jī)提供的 -XX:PretenureSizeThreshold參數(shù)進(jìn)行配置坠七。
  4. 動(dòng)態(tài)對(duì)象年齡判定:如果在Survivor空間中相同年齡所有對(duì)象大小的總和大于Survivor空間的一半,年齡大于或等于該年齡的對(duì)象就可以直接進(jìn)入老年代旗笔,無(wú)需等到到達(dá)3中的PretenureSizeThreshold參數(shù)闕值彪置。
標(biāo)記 - 整理算法

標(biāo)記過(guò)程仍然與“標(biāo)記-清除”算法一樣,但后續(xù)步驟不是直接對(duì)可回收對(duì)象進(jìn)行清理蝇恶,而是讓所有存活的對(duì)象都向一端移動(dòng)拳魁,然后直接清理掉端邊界以外的內(nèi)存,“標(biāo)記-整理”算法的示意圖如圖所示:


image.png

“標(biāo)記-整理”回收策略較大的問(wèn)題在于執(zhí)行效率撮弧,因?yàn)榇蠖夹枰啻螔呙瓒雅税茫菀自斐蒰c卡頓時(shí)間較長(zhǎng)

分代收集算法

當(dāng)前商業(yè)虛擬機(jī)的垃圾收集都采用“分代收集”(Generational Collection)算法,這種算法并沒(méi)有什么新的思想贿衍,只是根據(jù)對(duì)象存活周期的不同將內(nèi)存劃分為幾塊授舟。一般是把Java堆分為新生代和老年代,這樣就可以根據(jù)各個(gè)年代的特點(diǎn)采用最適當(dāng)?shù)氖占惴潮病T谛律惺褪鳎看卫占瘯r(shí)都發(fā)現(xiàn)有大批對(duì)象死去,只有少量存活,那就選用復(fù)制算法奢啥,只需要付出少量存活對(duì)象的復(fù)制成本就可以完成收集秸仙。而老年代中因?yàn)閷?duì)象存活率高、沒(méi)有額外空間對(duì)它進(jìn)行分配擔(dān)保桩盲,就必須使用“標(biāo)記—清理”或者“標(biāo)記—整理”算法來(lái)進(jìn)行回收寂纪。

WHEN:什么時(shí)候回收

Minor GC觸發(fā)條件:當(dāng)Eden區(qū)滿時(shí),觸發(fā)Minor GC正驻。
Full GC(或者M(jìn)ajor GC)觸發(fā)條件:
\blacksquare 程序顯式調(diào)用System.gc時(shí)弊攘,系統(tǒng)建議執(zhí)行Full GC
\blacksquare 方法區(qū)空間不足
\blacksquare 老年代空間不足
\blacksquare 通過(guò)Minor GC后進(jìn)入老年代的對(duì)象大小大于老年代的可用內(nèi)存
\blacksquare 由Eden區(qū)、From Space區(qū)向To Space區(qū)復(fù)制時(shí)姑曙,對(duì)象大小大于To Space可用內(nèi)存襟交,則把該對(duì)象轉(zhuǎn)存到老年代,且老年代的可用內(nèi)存小于該對(duì)象大小伤靠。

*關(guān)于JVM的GC過(guò)程捣域,推薦個(gè)感覺(jué)比較好的文章,里面有詳盡的圖文介紹:https://blog.csdn.net/weixin_39788856/article/details/80388002

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末宴合,一起剝皮案震驚了整個(gè)濱河市焕梅,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌卦洽,老刑警劉巖贞言,帶你破解...
    沈念sama閱讀 221,820評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異阀蒂,居然都是意外死亡该窗,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,648評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門蚤霞,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)酗失,“玉大人,你說(shuō)我怎么就攤上這事昧绣」骐龋” “怎么了?”我有些...
    開封第一講書人閱讀 168,324評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵夜畴,是天一觀的道長(zhǎng)拖刃。 經(jīng)常有香客問(wèn)我,道長(zhǎng)贪绘,這世上最難降的妖魔是什么序调? 我笑而不...
    開封第一講書人閱讀 59,714評(píng)論 1 297
  • 正文 為了忘掉前任,我火速辦了婚禮兔簇,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己垄琐,他們只是感情好边酒,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,724評(píng)論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著狸窘,像睡著了一般墩朦。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上翻擒,一...
    開封第一講書人閱讀 52,328評(píng)論 1 310
  • 那天氓涣,我揣著相機(jī)與錄音,去河邊找鬼陋气。 笑死劳吠,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的巩趁。 我是一名探鬼主播痒玩,決...
    沈念sama閱讀 40,897評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼议慰!你這毒婦竟也來(lái)了蠢古?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,804評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤别凹,失蹤者是張志新(化名)和其女友劉穎草讶,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體炉菲,經(jīng)...
    沈念sama閱讀 46,345評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡堕战,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,431評(píng)論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了颁督。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片践啄。...
    茶點(diǎn)故事閱讀 40,561評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖沉御,靈堂內(nèi)的尸體忽然破棺而出屿讽,到底是詐尸還是另有隱情,我是刑警寧澤吠裆,帶...
    沈念sama閱讀 36,238評(píng)論 5 350
  • 正文 年R本政府宣布伐谈,位于F島的核電站,受9級(jí)特大地震影響试疙,放射性物質(zhì)發(fā)生泄漏诵棵。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,928評(píng)論 3 334
  • 文/蒙蒙 一祝旷、第九天 我趴在偏房一處隱蔽的房頂上張望履澳。 院中可真熱鬧嘶窄,春花似錦、人聲如沸距贷。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,417評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)忠蝗。三九已至现横,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間阁最,已是汗流浹背戒祠。 一陣腳步聲響...
    開封第一講書人閱讀 33,528評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留速种,地道東北人姜盈。 一個(gè)月前我還...
    沈念sama閱讀 48,983評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像哟旗,于是被迫代替她去往敵國(guó)和親贩据。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,573評(píng)論 2 359

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