java9系列(九)Make G1 the Default Garbage Collector

本文主要研究下JEP 248: Make G1 the Default Garbage Collector

默認(rèn)垃圾收集器

java9廢棄了CMS垃圾收集器,并把G1提升為默認(rèn)垃圾收集器,替代了原來的吞吐優(yōu)先的ParallelOldGC

Region

G1相對(duì)于之前的垃圾收集器最大的不同是引入了Region。G1雖然也是基于分代機(jī)制血久,但是各個(gè)generation的空間不再連續(xù),如下圖:


image

可以用-XX:G1HeapRegionSize=16m來指定Region Size,注意它必須是2的乘方牌柄,范圍在1MB到32MB之間。目標(biāo)是根據(jù)最小的Java堆大小劃分出約2048 個(gè)區(qū)域.

Min Heap Size Region Size
heap < 4GB 1MB
4GB <= heap < 8GB 2MB
8GB <= heap < 16GB 4MB
16GB <= heap < 32GB 8MB
32GB <= heap < 64GB 16MB
64GB <= heap 32MB

如果沒有明確指定侧甫,則自動(dòng)根據(jù)Heap Size來指定珊佣,其對(duì)應(yīng)關(guān)系如下:

Min Heap Size Region Size
heap < 4GB 1MB
4GB <= heap < 8GB 2MB
8GB <= heap < 16GB 4MB
16GB <= heap < 32GB 8MB
32GB <= heap < 64GB 16MB
64GB <= heap 32MB

Humongous Object/ Humongous區(qū)域

  • 對(duì)于G1 GC,任何超過區(qū)域一半大小的對(duì)象都被視為“巨型對(duì)象”披粟。
  • 此類對(duì)象直接被分配到老年代中的“巨型區(qū)域”咒锻。
  • 這些巨型區(qū)域是一個(gè)連續(xù)的區(qū)域集。StartsHumongous 標(biāo)記該連續(xù)集的開始守屉,ContinuesHumongous 標(biāo)記它的延續(xù)惑艇。

巨型對(duì)象默認(rèn)直接會(huì)被分配在年老代,但是如果它是一個(gè)短期存在的巨型對(duì)象,就會(huì)對(duì)垃圾收集器造成負(fù)面影響滨巴。為了解決這個(gè)問題思灌,G1劃分了一個(gè)Humongous區(qū),它用來專門存放巨型對(duì)象恭取。如果一個(gè)H區(qū)裝不下一個(gè)巨型對(duì)象泰偿,那么G1會(huì)尋找連續(xù)的H分區(qū)來存儲(chǔ)。為了能找到連續(xù)的H區(qū)蜈垮,有時(shí)候不得不啟動(dòng)Full GC耗跛。

GC事件及觸發(fā)

GC event

  • Minor GC event

正常的young gc

  • Mixed GC event

Minor GC + (# reclaimable Tenured regions / -XX:G1MixedGCCountTarget) regions of Tenured

  • Full GC event

All regions evacuated,通常Humongous object太多會(huì)耗盡空間攒发,導(dǎo)致Full GC

  • Minor/Mixed + To-space exhaustion

Minor/Mixed + rollback + Full GC

觸發(fā)時(shí)機(jī)

  • Eden滿/空間不夠
  • 剩余空間不夠容納一個(gè)Humongous object
  • Humongous object分配成功调塌,同時(shí)符合一些GC條件
  • 外部命令觸發(fā)(jcmd, jmap, Runtime.gc())

G1 GC分類

主要分為:Minor GC,Mixed/Old GC

Minor GC/Young GC(STW)

Young GC主要是對(duì)Eden區(qū)進(jìn)行GC惠猿,它在Eden空間不夠時(shí)會(huì)被觸發(fā)羔砾。Eden空間的數(shù)據(jù)移動(dòng)到Survivor空間中,如果Survivor空間不夠紊扬,Eden空間的部分?jǐn)?shù)據(jù)會(huì)直接晉升到年老代空間蜒茄。From Survivor區(qū)的數(shù)據(jù)移動(dòng)到To Survivor區(qū)中,也有部分?jǐn)?shù)據(jù)晉升到老年代空間中餐屎。

階段 執(zhí)行動(dòng)作
階段1 根掃描 靜態(tài)和本地對(duì)象被掃描
階段2 更新RS 處理dirty card隊(duì)列更新RS
階段3 處理RS 檢測(cè)從年輕代指向年老代的對(duì)象
階段4 對(duì)象拷貝 拷貝存活的對(duì)象到survivor/old區(qū)域
階段5 處理引用隊(duì)列 軟引用檀葛,弱引用,虛引用處理

其階段主要如下:

階段 執(zhí)行動(dòng)作
階段1 根掃描 靜態(tài)和本地對(duì)象被掃描
階段2 更新RS 處理dirty card隊(duì)列更新RS
階段3 處理RS 檢測(cè)從年輕代指向年老代的對(duì)象
階段4 對(duì)象拷貝 拷貝存活的對(duì)象到survivor/old區(qū)域
階段5 處理引用隊(duì)列 軟引用腹缩,弱引用屿聋,虛引用處理

Mixed/Old GC(STW)

主要是對(duì)年老代進(jìn)行并發(fā)標(biāo)記然后進(jìn)行GC,其中部分階段涉及到y(tǒng)gc藏鹊,同時(shí)既有ygc及old gc的部分稱為mixed gc润讥。

階段 執(zhí)行動(dòng)作
(1) Initial Mark(Stop the World Event) 初始標(biāo)記階段 在此階段G1 GC對(duì)根進(jìn)行標(biāo)記。該階段與常規(guī)的 (STW) 年輕代垃圾回收密切相關(guān)盘寡。日志標(biāo)記為Pause Initial Mark (G1 Evacuation Pause).
(2) Root Region Scanning 根區(qū)域掃描階段 G1 GC在初始標(biāo)記的存活區(qū)掃描對(duì)老年代的引用楚殿,并標(biāo)記被引用的對(duì)象。該階段與應(yīng)用程序(非 STW)同時(shí)運(yùn)行竿痰,并且只有完成該階段后脆粥,才能開始下一次STW年輕代垃圾回收。
(3) Concurrent Marking 并發(fā)標(biāo)記階段 G1 GC在整個(gè)堆中查找可訪問的(存活的)對(duì)象影涉。該階段與應(yīng)用程序同時(shí)運(yùn)行变隔,可以被 STW 年輕代垃圾回收中斷。
(4) Remark(Stop the World Event) 重新標(biāo)記階段 該階段是STW回收蟹倾,幫助完成標(biāo)記周期匣缘。G1 GC清空SATB緩沖區(qū)猖闪,跟蹤未被訪問的存活對(duì)象,并執(zhí)行引用處理肌厨。
(5) Copying(Stop the World Event) / Cleanup(Stop the World Event and Concurrent) 拷貝/清理階段 在這個(gè)最后階段培慌,G1 GC為了更快進(jìn)行垃圾回收,會(huì)選擇那些存活率低的region進(jìn)行拷貝柑爸,即evacuate或者拷貝存活對(duì)象到新的空閑的regions检柬,然后清理回收該region,此時(shí)會(huì)STW竖配,如果是在年輕代產(chǎn)生的,則日志標(biāo)記為Pause Young (G1 Evacuation Pause)里逆,如果年輕代和年老代都進(jìn)行這個(gè)動(dòng)作进胯,則日志標(biāo)記為Pause Mixed (G1 Evacuation Pause).

并發(fā)標(biāo)記周期(Concurrent Marking Cycle Phases)階段如下:

階段 執(zhí)行動(dòng)作
(1) Initial Mark(Stop the World Event) 初始標(biāo)記階段 在此階段G1 GC對(duì)根進(jìn)行標(biāo)記。該階段與常規(guī)的 (STW) 年輕代垃圾回收密切相關(guān)原押。日志標(biāo)記為Pause Initial Mark (G1 Evacuation Pause).
(2) Root Region Scanning 根區(qū)域掃描階段 G1 GC在初始標(biāo)記的存活區(qū)掃描對(duì)老年代的引用胁镐,并標(biāo)記被引用的對(duì)象。該階段與應(yīng)用程序(非 STW)同時(shí)運(yùn)行诸衔,并且只有完成該階段后盯漂,才能開始下一次STW年輕代垃圾回收。
(3) Concurrent Marking 并發(fā)標(biāo)記階段 G1 GC在整個(gè)堆中查找可訪問的(存活的)對(duì)象笨农。該階段與應(yīng)用程序同時(shí)運(yùn)行就缆,可以被 STW 年輕代垃圾回收中斷。
(4) Remark(Stop the World Event) 重新標(biāo)記階段 該階段是STW回收谒亦,幫助完成標(biāo)記周期竭宰。G1 GC清空SATB緩沖區(qū),跟蹤未被訪問的存活對(duì)象份招,并執(zhí)行引用處理切揭。
(5) Copying(Stop the World Event) / Cleanup(Stop the World Event and Concurrent) 拷貝/清理階段 在這個(gè)最后階段,G1 GC為了更快進(jìn)行垃圾回收锁摔,會(huì)選擇那些存活率低的region進(jìn)行拷貝廓旬,即evacuate或者拷貝存活對(duì)象到新的空閑的regions,然后清理回收該region谐腰,此時(shí)會(huì)STW孕豹,如果是在年輕代產(chǎn)生的,則日志標(biāo)記為Pause Young (G1 Evacuation Pause)怔蚌,如果年輕代和年老代都進(jìn)行這個(gè)動(dòng)作巩步,則日志標(biāo)記為Pause Mixed (G1 Evacuation Pause).

核心的階段主要是Concurrent Marking Phase、Remark Phase桦踊、Copying/Cleanup Phase

相關(guān)參數(shù)

參數(shù) 含義
-XX:G1HeapRegionSize=n 設(shè)置Region大小椅野,并非最終值
-XX:MaxGCPauseMillis=200 設(shè)置G1收集過程目標(biāo)時(shí)間,默認(rèn)值200ms,不是硬性條件
-XX:G1NewSizePercent=5 新生代最小值竟闪,默認(rèn)值5%
-XX:G1MaxNewSizePercent=60 新生代最大值离福,默認(rèn)值60%
-XX:ParallelGCThreads=n STW期間,并行GC線程數(shù)炼蛤,其值與邏輯處理器的數(shù)量相同妖爷,最多為8。如果邏輯處理器不止八個(gè)理朋,則將n為邏輯處理器數(shù)的5/8
-XX:ConcGCThreads=n 并發(fā)標(biāo)記階段的并行標(biāo)記線程數(shù)絮识,ParallelGCThreads的 1/4 左右
-XX:InitiatingHeapOccupancyPercent=45 設(shè)置觸發(fā)標(biāo)記周期的Java堆占用率閾值。默認(rèn)值是45%嗽上。這里的java堆占比指的是non_young_capacity_bytes次舌,包括old+humongous
-XX:G1MixedGCLiveThresholdPercent=65 為混合垃圾回收周期中要包括的舊區(qū)域設(shè)置占用率閾值。默認(rèn)占用率為 65%
-XX:G1HeapWastePercent=10 如果可回收百分比小于此值兽愤,JVM不會(huì)啟動(dòng)混合垃圾回收周期彼念。默認(rèn)值是10%
-XX:G1OldCSetRegionThresholdPercent=10 設(shè)置混合垃圾回收期間要回收的最大舊區(qū)域數(shù)。默認(rèn)值是Java堆的10%
-XX:G1MixedGCCountTarget=8 設(shè)置標(biāo)記周期完成后浅萧,對(duì)存活數(shù)據(jù)上限為 G1MixedGCLIveThresholdPercent 的舊區(qū)域執(zhí)行混合垃圾回收的目標(biāo)次數(shù)逐沙。默認(rèn)8次混合垃圾回收,混合回收的目標(biāo)是要控制在此目標(biāo)次數(shù)以內(nèi)
-XX:G1ReservePercent=10 設(shè)置作為空閑空間的預(yù)留內(nèi)存百分比洼畅,以降低目標(biāo)空間溢出的風(fēng)險(xiǎn)吩案。默認(rèn)值是10%。增加或減少百分比時(shí)土思,請(qǐng)確保對(duì)總的Java 堆調(diào)整相同的量

避免使用-Xmn選項(xiàng)或-XX:NewRatio等其他相關(guān)選項(xiàng)顯式設(shè)置年輕代大小务热,固定年輕代的大小會(huì)禁用掉暫停時(shí)間(MaxGCPauseMillis)目標(biāo)。

GC日志實(shí)例

簡(jiǎn)版使用-Xlog:gc=info己儒,詳細(xì)版使用-Xlog:gc*=info

ygc

  • 簡(jiǎn)版
[0.317s][info][gc] GC(37) Pause Young (G1 Evacuation Pause) 7M->6M(10M) 0.511ms
[0.324s][info][gc] GC(40) Pause Young (G1 Evacuation Pause) 7M->6M(10M) 0.709ms
  • 詳細(xì)版
[0.011s][info][gc,heap] Heap region size: 1M
[0.012s][info][gc     ] Using G1
[0.012s][info][gc,heap,coops] Heap address: 0x00000007bf600000, size: 10 MB, Compressed Oops mode: Zero based, Oop shift amount: 3
[0.170s][info][gc,start     ] GC(0) Pause Young (G1 Evacuation Pause)
[0.170s][info][gc,task      ] GC(0) Using 8 workers of 8 for evacuation
[0.172s][info][gc,phases    ] GC(0)   Pre Evacuate Collection Set: 0.0ms
[0.172s][info][gc,phases    ] GC(0)   Evacuate Collection Set: 1.5ms
[0.172s][info][gc,phases    ] GC(0)   Post Evacuate Collection Set: 0.1ms
[0.172s][info][gc,phases    ] GC(0)   Other: 0.1ms
[0.172s][info][gc,heap      ] GC(0) Eden regions: 4->0(2)
[0.172s][info][gc,heap      ] GC(0) Survivor regions: 0->1(1)
[0.172s][info][gc,heap      ] GC(0) Old regions: 0->1
[0.172s][info][gc,heap      ] GC(0) Humongous regions: 0->0
[0.172s][info][gc,metaspace ] GC(0) Metaspace: 5982K->5982K(1056768K)
[0.172s][info][gc           ] GC(0) Pause Young (G1 Evacuation Pause) 4M->1M(10M) 1.718ms
[0.172s][info][gc,cpu       ] GC(0) User=0.01s Sys=0.00s Real=0.00s

old gc

  • 簡(jiǎn)版
[0.321s][info][gc] GC(38) Pause Initial Mark (G1 Evacuation Pause) 7M->6M(10M) 0.601ms
[0.321s][info][gc] GC(39) Concurrent Cycle
[0.324s][info][gc] GC(40) Pause Young (G1 Evacuation Pause) 7M->6M(10M) 0.709ms
[0.326s][info][gc] GC(39) Pause Remark 7M->7M(10M) 0.623ms
[0.326s][info][gc] GC(39) Pause Cleanup 7M->7M(10M) 0.104ms
[0.326s][info][gc] GC(39) Concurrent Cycle 5.398ms
[0.327s][info][gc] GC(41) Pause Young (G1 Evacuation Pause) 7M->6M(10M) 0.512ms
[0.331s][info][gc] GC(42) To-space exhausted
[0.331s][info][gc] GC(42) Pause Mixed (G1 Evacuation Pause) 7M->7M(10M) 1.190ms
[0.334s][info][gc] GC(43) Pause Initial Mark (G1 Evacuation Pause) 8M->7M(10M) 0.637ms
[0.334s][info][gc] GC(44) Concurrent Cycle
[0.338s][info][gc] GC(45) Pause Young (G1 Evacuation Pause) 8M->7M(10M) 0.553ms
[0.340s][info][gc] GC(44) Pause Remark 8M->8M(10M) 0.582ms
[0.341s][info][gc] GC(44) Pause Cleanup 8M->8M(10M) 0.100ms
[0.341s][info][gc] GC(44) Concurrent Cycle 6.195ms
  • 詳細(xì)版
[0.942s][info][gc,start       ] GC(192) Pause Initial Mark (G1 Evacuation Pause)
[0.942s][info][gc,task        ] GC(192) Using 8 workers of 8 for evacuation
[0.942s][info][gc,phases      ] GC(192)   Pre Evacuate Collection Set: 0.0ms
[0.942s][info][gc,phases      ] GC(192)   Evacuate Collection Set: 0.4ms
[0.942s][info][gc,phases      ] GC(192)   Post Evacuate Collection Set: 0.0ms
[0.942s][info][gc,phases      ] GC(192)   Other: 0.0ms
[0.942s][info][gc,heap        ] GC(192) Eden regions: 0->0(1)
[0.942s][info][gc,heap        ] GC(192) Survivor regions: 0->0(1)
[0.942s][info][gc,heap        ] GC(192) Old regions: 10->10
[0.942s][info][gc,heap        ] GC(192) Humongous regions: 0->0
[0.942s][info][gc,metaspace   ] GC(192) Metaspace: 5993K->5993K(1056768K)
[0.942s][info][gc             ] GC(192) Pause Initial Mark (G1 Evacuation Pause) 9M->9M(10M) 0.530ms
[0.942s][info][gc,cpu         ] GC(192) User=0.00s Sys=0.00s Real=0.00s
[0.942s][info][gc             ] GC(193) Concurrent Cycle
[0.942s][info][gc,marking     ] GC(193) Concurrent Clear Claimed Marks
[0.942s][info][gc,marking     ] GC(193) Concurrent Clear Claimed Marks 0.004ms
[0.942s][info][gc,marking     ] GC(193) Concurrent Scan Root Regions
[0.942s][info][gc,marking     ] GC(193) Concurrent Scan Root Regions 0.003ms
[0.942s][info][gc,marking     ] GC(193) Concurrent Mark (0.942s)
[0.942s][info][gc,marking     ] GC(193) Concurrent Mark From Roots
[0.942s][info][gc,task        ] GC(193) Using 2 workers of 2 for marking
[0.942s][info][gc,start       ] GC(194) Pause Full (Allocation Failure)
[0.943s][info][gc,phases,start] GC(194) Phase 1: Mark live objects
[0.946s][info][gc,stringtable ] GC(194) Cleaned string and symbol table, strings: 3222 processed, 0 removed, symbols: 25923 processed, 0 removed
[0.946s][info][gc,phases      ] GC(194) Phase 1: Mark live objects 3.168ms
[0.946s][info][gc,phases,start] GC(194) Phase 2: Compute new object addresses
[0.946s][info][gc,phases      ] GC(194) Phase 2: Compute new object addresses 0.418ms
[0.946s][info][gc,phases,start] GC(194) Phase 3: Adjust pointers
[0.949s][info][gc,phases      ] GC(194) Phase 3: Adjust pointers 2.706ms
[0.949s][info][gc,phases,start] GC(194) Phase 4: Move objects
[0.949s][info][gc,phases      ] GC(194) Phase 4: Move objects 0.005ms
[0.949s][info][gc,task        ] GC(194) Using 8 workers of 8 to rebuild remembered set
[0.951s][info][gc,heap        ] GC(194) Eden regions: 0->0(1)
[0.951s][info][gc,heap        ] GC(194) Survivor regions: 0->0(1)
[0.951s][info][gc,heap        ] GC(194) Old regions: 10->10
[0.951s][info][gc,heap        ] GC(194) Humongous regions: 0->0
[0.951s][info][gc,metaspace   ] GC(194) Metaspace: 5993K->5993K(1056768K)
[0.951s][info][gc             ] GC(194) Pause Full (Allocation Failure) 9M->9M(10M) 8.955ms
[0.951s][info][gc,cpu         ] GC(194) User=0.01s Sys=0.00s Real=0.01s

小結(jié)

G1收集器博大精深崎岂,有待進(jìn)一步實(shí)踐進(jìn)行深入理解研究。

doc

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末闪湾,一起剝皮案震驚了整個(gè)濱河市冲甘,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌途样,老刑警劉巖江醇,帶你破解...
    沈念sama閱讀 217,542評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異何暇,居然都是意外死亡陶夜,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門裆站,熙熙樓的掌柜王于貴愁眉苦臉地迎上來条辟,“玉大人黔夭,你說我怎么就攤上這事∮鸬眨” “怎么了本姥?”我有些...
    開封第一講書人閱讀 163,912評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)杭棵。 經(jīng)常有香客問我婚惫,道長(zhǎng),這世上最難降的妖魔是什么魂爪? 我笑而不...
    開封第一講書人閱讀 58,449評(píng)論 1 293
  • 正文 為了忘掉前任先舷,我火速辦了婚禮,結(jié)果婚禮上滓侍,老公的妹妹穿的比我還像新娘密浑。我一直安慰自己,他們只是感情好粗井,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,500評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著街图,像睡著了一般浇衬。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上餐济,一...
    開封第一講書人閱讀 51,370評(píng)論 1 302
  • 那天耘擂,我揣著相機(jī)與錄音,去河邊找鬼絮姆。 笑死醉冤,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的篙悯。 我是一名探鬼主播蚁阳,決...
    沈念sama閱讀 40,193評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼鸽照!你這毒婦竟也來了螺捐?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,074評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤矮燎,失蹤者是張志新(化名)和其女友劉穎定血,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體诞外,經(jīng)...
    沈念sama閱讀 45,505評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡澜沟,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,722評(píng)論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了峡谊。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片茫虽。...
    茶點(diǎn)故事閱讀 39,841評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡刊苍,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出席噩,到底是詐尸還是另有隱情班缰,我是刑警寧澤,帶...
    沈念sama閱讀 35,569評(píng)論 5 345
  • 正文 年R本政府宣布悼枢,位于F島的核電站埠忘,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏馒索。R本人自食惡果不足惜莹妒,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,168評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望绰上。 院中可真熱鬧旨怠,春花似錦、人聲如沸蜈块。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽百揭。三九已至爽哎,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間器一,已是汗流浹背课锌。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評(píng)論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留祈秕,地道東北人渺贤。 一個(gè)月前我還...
    沈念sama閱讀 47,962評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像请毛,于是被迫代替她去往敵國和親志鞍。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,781評(píng)論 2 354

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