假期后來一波干貨:一文理清JVM和GC

本文主要介紹 JVM和GC解析
如有需要,可以參考
如有幫助担猛,不忘 點(diǎn)贊 ?

創(chuàng)作不易幕垦,白嫖無義!

一傅联、JVM內(nèi)存體系

其中方法區(qū)被JVM中多個(gè)線程共享先改,比如類的靜態(tài)常量就被存放在方法區(qū),供類對(duì)象之間共享蒸走。

虛擬機(jī)棧仇奶、本地方法棧程序計(jì)數(shù)器是每個(gè)線程獨(dú)立擁有的比驻,不會(huì)與其他線程共享该溯。

所以Java在通過new創(chuàng)建一個(gè)類對(duì)象實(shí)例的時(shí)候岛抄,一方面會(huì)在虛擬機(jī)棧中創(chuàng)建一個(gè)對(duì)該對(duì)象的引用,另一方面會(huì)在堆上創(chuàng)建類對(duì)象的實(shí)例狈茉,然后將對(duì)象引用指向該對(duì)象的實(shí)例夫椭。對(duì)象引用存放在每一個(gè)方法對(duì)應(yīng)的棧幀中。

假期后來一波干貨:一文理清JVM和GC
  • 虛擬機(jī)棧:虛擬機(jī)棧中執(zhí)行每個(gè)方法的時(shí)候氯庆,都會(huì)創(chuàng)建一個(gè)棧幀用于存儲(chǔ)局部變量表蹭秋,操作數(shù)棧,動(dòng)態(tài)鏈接点晴,方法出口等信息感凤。
  • 本地方法棧:與虛擬機(jī)棧發(fā)揮的作用相似,相比于虛擬機(jī)棧為Java方法服務(wù)粒督,本地方法棧為虛擬機(jī)使用的Native方法服務(wù)陪竿,執(zhí)行每個(gè)本地方法的時(shí)候,都會(huì)創(chuàng)建一個(gè)棧幀用于存儲(chǔ)局部變量表屠橄,操作數(shù)棧族跛,動(dòng)態(tài)鏈接,方法出口等信息锐墙。
  • 方法區(qū):它用于存儲(chǔ)已被虛擬機(jī)加載的類信息礁哄,常量,靜態(tài)變量溪北,即時(shí)編譯器編譯后的代碼等數(shù)據(jù)桐绒,方法區(qū)在JDK1.7版本及之前稱為永久代,從JDK1.8之后永久代被移除之拨。
  • 堆:堆是Java對(duì)象的存儲(chǔ)區(qū)域茉继,任何new字段分配的Java對(duì)象實(shí)例和數(shù)組,都被分配在了堆上蚀乔,Java堆可使用 - Xms 和-Xmx 進(jìn)行內(nèi)存控制烁竭,從JDK1.7版本之后,運(yùn)行時(shí)常量池從方法區(qū)移到了堆上吉挣。
  • 程序計(jì)數(shù)器:指示Java虛擬機(jī)下一條需要執(zhí)行的字節(jié)碼指令派撕。

二、JAVA8之后的JVM

從圖中我們可以看出JAVA8的JVM 用元空間取代了永久代

假期后來一波干貨:一文理清JVM和GC
假期后來一波干貨:一文理清JVM和GC
image.png

三睬魂、GC作用域

假期后來一波干貨:一文理清JVM和GC

四终吼、常見垃圾回收算法

引用計(jì)數(shù)法:

JVM的實(shí)現(xiàn)一般不采用這種方式

假期后來一波干貨:一文理清JVM和GC

缺點(diǎn)

  • 每次對(duì)對(duì)象賦值時(shí)均要維護(hù)引用計(jì)數(shù)器,且計(jì)數(shù)器本身也有一定的消耗氯哮;
  • 較難處理循環(huán)引用衔峰;

復(fù)制算法:

Java 而從GC的角度可以細(xì)分為:新生代(Eden區(qū)、From Survivor區(qū) 和 To Survivor區(qū))和 老年代。
特點(diǎn)
復(fù)制算法不會(huì)產(chǎn)生內(nèi)存碎片垫卤,但會(huì)占用空間。用于新生代出牧。

image.png

MinorGC的過程(復(fù)制 --> 清空 --> 互換)

  1. 復(fù)制: (Eden穴肘、SurvivorFrom 復(fù)制到 SurvivorTo,年齡加1)
    首先舔痕,當(dāng)Eden區(qū)滿的時(shí)候會(huì)觸發(fā)第一次GC评抚,把還活著的對(duì)象拷貝到SurvivorFrom區(qū),當(dāng)Eden區(qū)再次觸發(fā)GC的時(shí)候會(huì)掃描Eden區(qū)域和From區(qū)域伯复,對(duì)這兩個(gè)區(qū)域進(jìn)行垃圾回收慨代,經(jīng)過這次回收后還存活的對(duì)象,則直接復(fù)制到To區(qū)域(如果有對(duì)象的年齡已經(jīng)到達(dá)了老年的標(biāo)準(zhǔn)啸如,則復(fù)制到老年代區(qū))侍匙,同時(shí)把這些對(duì)象的年齡加1。
  2. 清空:(清空Eden叮雳、SurvivorFrom)
    清空Eden和SurvivorFrom中的對(duì)象想暗,也即復(fù)制之后有交換,誰空誰是to帘不。
  3. 互換:(SurvivorTo和SurvivorFrom 互換)
    最后说莫,SurvivorTo和SurvivorFrom 互換,原SurvivorTo成為下一次GC是的SurvivorFrom區(qū)寞焙。

標(biāo)記清除法

算法分成標(biāo)記和清除兩個(gè)階段储狭,先標(biāo)記出要回收的對(duì)象,然后統(tǒng)一回收這些捣郊。
特點(diǎn)
不會(huì)占用額外空間辽狈,但會(huì)掃描兩次,耗時(shí)模她,容易產(chǎn)生碎片稻艰,用于老年代

假期后來一波干貨:一文理清JVM和GC

標(biāo)記壓縮法

優(yōu)點(diǎn)
沒有內(nèi)存碎片,可以利用bump
缺點(diǎn)
需要移動(dòng)對(duì)象的成本侈净,用于老年代
原理

標(biāo)記:與標(biāo)記清除一樣

image.png

壓縮:再次掃描尊勿,并往一段滑動(dòng)存活對(duì)象

假期后來一波干貨:一文理清JVM和GC

五、判斷對(duì)象是否可回收

引用計(jì)數(shù)法

Java中畜侦,引用和對(duì)象是有關(guān)聯(lián)的元扔。如果要操作對(duì)象則必須用引用進(jìn)行。
因此旋膳,很顯然的一個(gè)方法就是通過引用計(jì)數(shù)來判斷一個(gè)對(duì)象是否可以回收澎语。簡單來說就是給對(duì)象添加一個(gè)引用計(jì)數(shù)器。每當(dāng)有一個(gè)地方引用它,計(jì)數(shù)器的值加1擅羞,每當(dāng)有一個(gè)引用失效時(shí)尸变,計(jì)數(shù)器的值減1。
任何時(shí)刻計(jì)數(shù)器值為0的對(duì)象就是不可能再被使用的减俏,那么這個(gè)對(duì)象就是可回收對(duì)象召烂。
缺點(diǎn)

很難解決對(duì)象之間相互循環(huán)引用的問題

枚舉根節(jié)點(diǎn)做可達(dá)性分析(根搜索路徑)

所謂GC roots或者說tracing GC 的 根集合 就是一組必須活躍的引用。
基本思路就是通過一系列名為GC Root 的對(duì)象作為起始點(diǎn)娃承,從這個(gè)被稱為GC Roots的對(duì)象開始向下搜索奏夫。

如GC Roots沒有任何引用鏈相連是,則說明此對(duì)象不可用历筝。也即給定一個(gè)集合的引用作為根出發(fā)酗昼,通過引用關(guān)系

假期后來一波干貨:一文理清JVM和GC

哪些可以做GCRoots對(duì)象

  • 虛擬機(jī)棧(棧幀中的局部變量區(qū),也叫做局部變量表)
  • 方法區(qū)中的類靜態(tài)屬性引用的對(duì)象
  • 方法區(qū)中常量引用的對(duì)象
  • 本地方法棧中N(Native方法)引用的對(duì)象

六梳猪、JVM的參數(shù)類型

1)標(biāo)配參數(shù)

  • java -version
  • java -help
image.png

2)X參數(shù)

  • java -Xint -version :解釋執(zhí)行
  • java -Xcomp -version :第一次使用就編譯成本地代碼
  • java -Xmixed :混合模式
假期后來一波干貨:一文理清JVM和GC

3)XX參數(shù)

  • Boolean類型

-XX:+ 或者 - 某個(gè)屬性值(+:表示開啟麻削,-:表示關(guān)閉)
例子
-XX: +PrintGCDetails: 開啟打印GC收集細(xì)節(jié)
-XX: -PrintGCDetails: 關(guān)閉打印GC收集細(xì)節(jié)
-XX: +UseSerialGC: 開啟串行垃圾收集器
-XX: -UseSerialGC:關(guān)閉串行垃圾收集器

  • KV設(shè)置類型

-XX: 屬性key = 屬性value
例子
-XX: MetaspaceSize = 128m:設(shè)置元空間大小為128m
-XX:MaxTenuringThreshold = 15:控制新生代需要經(jīng)歷多少次GC晉升到老年代中的最大閾值

  • jinfo -查看當(dāng)前運(yùn)行程序的配置

公式:jinfo -flag 配置項(xiàng) 進(jìn)程編號(hào)
例子

  1. 查看初始堆大小:
假期后來一波干貨:一文理清JVM和GC

2.查看其他參數(shù)

假期后來一波干貨:一文理清JVM和GC

3.查看使用哪種垃圾回收器

假期后來一波干貨:一文理清JVM和GC

兩個(gè)經(jīng)典參數(shù)

  • -Xms 等價(jià)于 -XX: InitialHeapSize
  • -Xmx 等價(jià)于 -XX: MaxHeapSize

七舔示、查看JVM默認(rèn)值

  • -XX:+PrintFlagsInitial: 查看默認(rèn)初始值

java -XX: +PrintFlagsInitial -version

java -XX: +PrintFlagsInitial

假期后來一波干貨:一文理清JVM和GC
  • -XX:+PrintFlagsFinal 查看修改更新
  • java -XX:+PrintFlagsFinal
  • java -XX:+PrintFlagsFinal -version
  • java -XX:+PrintCommandedLineFlags
假期后來一波干貨:一文理清JVM和GC

八碟婆、常用的配置參數(shù)

經(jīng)典案例設(shè)置
-Xms128m -Xmx4096m -Xss1024k -XX:Metaspacesize=512m -XX:+PrintCommandLineFlags -XX:PrintGCDetails -XX:UseSerialGC

  • -Xms

初始化大小內(nèi)存,默認(rèn)為物理內(nèi)存1/64
等價(jià)于 -XX:InitialHeapSize

  • -Xmx

最大分配內(nèi)存惕稻,默認(rèn)為物理內(nèi)存1/4
等價(jià)于 -XX:MaxHeapSize

  • -Xss

設(shè)置單個(gè)線程的大小竖共,一般默認(rèn)為5112K~1024K
等價(jià)于 -XX:ThreadStackSize

  • -Xmn

設(shè)置年輕代大小

  • -XX:MetaspaceSize

設(shè)置元空間大小

元空間的本質(zhì)和永久代類似,都是對(duì)JVM規(guī)范中方法區(qū)的實(shí)現(xiàn)俺祠,不過元空間與永久代之間最大的區(qū)別在于:元空間并不在虛擬機(jī)中公给,而是使用本地內(nèi)存。因此蜘渣,默認(rèn)情況下淌铐,元空間的大小僅受本地內(nèi)存限制

  • -XX:+PrintGCdetails

輸出詳細(xì)的GC收集日志信息

  • -XX:SurvivorRatio

設(shè)置新生代中eden和S0/S1空間的比例
默認(rèn):
-XX:SurvivorRatio=8 --> Eden:S0:S1=8:1:1
修改:
-XX:SurvivorRatio=4 --> Eden:S0:S1=4:1:1
SurvivorRatio值就是設(shè)置eden區(qū)的比例占多少蔫缸,S0/S1相同

  • -XX:NewRatio

設(shè)置年輕代與老年代在堆結(jié)構(gòu)的占比
默認(rèn):
-XX:NewRatio=2: 新生代占1腿准,老年代占2,年輕代占整個(gè)堆的1/3
修改:
-XX:NewRatio=4: 新生代占1拾碌,老年代占4吐葱,年輕代占整個(gè)堆的1/5
NewRatio值就是設(shè)置老年代的占比,剩下的1給新生代

  • -XX:MaxTenuringThreshold

設(shè)置垃圾最大年齡
-XX:MaxTenuringThreshold=0:設(shè)置垃圾最大年齡校翔。

如果設(shè)置為0的話弟跑,則年輕代對(duì)象不經(jīng)過Survivor區(qū),直接進(jìn)入老年代防症。對(duì)于老年代比較多的應(yīng)用孟辑,可以提高效率哎甲。如果將此值設(shè)置為一個(gè)較大值,則年輕代對(duì)象會(huì)在Survivor區(qū)進(jìn)行多次復(fù)制饲嗽,這樣可以增加對(duì)象在年輕代的存活時(shí)間炭玫,增加年輕代被回收的概論。

九貌虾、強(qiáng)軟弱虛

假期后來一波干貨:一文理清JVM和GC
假期后來一波干貨:一文理清JVM和GC

1)強(qiáng)引用

  • 當(dāng)內(nèi)存不足础嫡,JVM開始垃圾回收,對(duì)于強(qiáng)引用的對(duì)象酝惧,就算出現(xiàn)了OOM也不會(huì)對(duì)該對(duì)象進(jìn)行回收,死都不收
  • 強(qiáng)引用是我們最常見的普通對(duì)象引用伯诬,只要還有強(qiáng)引用指向一個(gè)對(duì)象晚唇,就能表明對(duì)象還活著,垃圾收集器不會(huì)碰這種對(duì)象盗似。在Java中最常見的就是強(qiáng)引用哩陕,把一個(gè)對(duì)象賦給一個(gè)引用變量,這個(gè)引用變量就是一個(gè)強(qiáng)引用赫舒。當(dāng)一個(gè)對(duì)象被強(qiáng)引用變量引用時(shí)悍及,它處于可達(dá)狀態(tài),它是不可能被垃圾回收機(jī)制回收的接癌。即使該對(duì)象以后永遠(yuǎn)都不會(huì)被用到心赶,JVM也不會(huì)回收。 因此強(qiáng)引用是造成Java內(nèi)存泄漏的主要原因之一缺猛。
  • 對(duì)于一個(gè)普通的對(duì)象缨叫,如果沒有其他的引用關(guān)系,只要超過了引用的作用域或者顯式地將相應(yīng)(強(qiáng))引用賦值為null荔燎,一般就是認(rèn)為可以被垃圾收集(具體看垃圾收集策略)
public static void main(String[] args) {
        Object o1 = new Object();   //默認(rèn)為強(qiáng)引用
        Object o2 = o1;     //引用賦值
        o1 = null;          //置空 讓垃圾收集
        System.gc();
        System.out.println(o1);     // null
        System.out.println(o2);     // java.lang.Object@1540e19d
    }
復(fù)制代碼

2)軟引用

  • 軟引用就是一種相對(duì)強(qiáng)引用弱化了一些的引用耻姥。需要用java.lang.ref.SoftReference類來實(shí)現(xiàn),可以讓對(duì)象豁免一些垃圾收集有咨。
  • 系統(tǒng)內(nèi)存充足 -> 不會(huì)回收
  • 系統(tǒng)內(nèi)存不足 -> 會(huì)回收
  • 軟引用通常用在對(duì)內(nèi)存敏感的程序中琐簇,比如高速緩存就有用到軟引用,內(nèi)存夠用的時(shí)候就保留座享,不夠用就回收
    public static void main(String[] args) {
        Object o1 = new Object();
        SoftReference softReference = new SoftReference(o1);
        o1 = null;
        System.gc();
        System.out.println(o1);
        System.out.println(softReference.get());
    }
復(fù)制代碼

3)弱引用

  • 弱引用需要用java.lang.ref.WeakReference類來實(shí)現(xiàn)婉商,它比軟引用的生存期更短
  • 對(duì)于弱引用的對(duì)象,只要垃圾回收機(jī)制一運(yùn)行征讲,不管JVM的內(nèi)存空間是否足夠据某,都會(huì)回收該對(duì)象占用的內(nèi)存。
    public static void main(String[] args) {
        Object o1 = new Object();
        WeakReference weakReference = new WeakReference(o1);
        o1 = null;
        System.gc();
        System.out.println(o1);                     //null
        System.out.println(weakReference.get());    //null
    }
復(fù)制代碼

5)虛引用

  • 虛引用需要java.lang.ref.PhantomReference類來實(shí)現(xiàn)诗箍。
  • 形如虛設(shè)癣籽,它不會(huì)決定對(duì)象的生命周期挽唉。
  • 如果一個(gè)對(duì)象持有虛引用,那么它就和沒有任何一樣筷狼,在任何時(shí)候都可能被垃圾回收器回收瓶籽,它不能單獨(dú)使用也不能通過它來訪問對(duì)象,虛引用必須和引用隊(duì)列(ReferenceQueue)聯(lián)合使用埂材。
  • 虛引用的主要作用是跟蹤對(duì)象被垃圾回收的狀態(tài)塑顺,僅僅是提供了一種確保對(duì)象被finalize以后,做某些事情的機(jī)制俏险。PhantomReference的get()方法總是返回null严拒,因此無法訪問對(duì)應(yīng)的引用對(duì)象。其意義在于說明一個(gè)對(duì)象已經(jīng)進(jìn)入finalization階段竖独,可以被gc回收裤唠,用來實(shí)現(xiàn)比finalization機(jī)制更靈活的回收操作。
public static void main(String[] args) {
        Object o1 = new Object();
        ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>();
        PhantomReference<Object> phantomReference = new PhantomReference<>(o1,referenceQueue);
        System.out.println(o1);                         //java.lang.Object@1540e19d
        System.out.println(phantomReference.get());     //null
        System.out.println(referenceQueue.poll());      //null
    }
復(fù)制代碼

擴(kuò)展:軟弱引用適用場(chǎng)景

假如有一個(gè)引用需要讀取大量的本地圖片
存在問題

  1. 如果每次讀取圖片都從硬盤讀取則會(huì)嚴(yán)重影響性能莹痢。
  2. 如果一次性全部加載到內(nèi)存中有可能造成內(nèi)存溢出种蘸。

解決思路
用一個(gè)HashMap來保存圖片的路徑和相應(yīng)圖片對(duì)象關(guān)聯(lián)的軟引用之間的映射關(guān)系,在內(nèi)存不足時(shí)竞膳,JVM會(huì)自動(dòng)回收這些緩存圖片對(duì)象所占用的空間航瞭,從而有效地避免了OOM的問題。
Map<String,SoftReference> imgMap = new HashMap<String,SoftReference>()

WeakHashMap:

public static void main(String[] args) {
        WeakHashMap<Integer,String> weakHashMap = new WeakHashMap<>();
        Integer key = new Integer(1);
        weakHashMap.put(key,"測(cè)試1");
        System.out.println(weakHashMap);    //{1=測(cè)試1}
        key=null;
        System.out.println(weakHashMap);    //{1=測(cè)試1}
        System.gc();
        System.out.println(weakHashMap+"\t"+weakHashMap.size());    //{} 0
    }
復(fù)制代碼
假期后來一波干貨:一文理清JVM和GC

看完不贊坦辟,都是壞蛋

原文鏈接:
https://juejin.cn/post/6844904116272136200

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末刊侯,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子长窄,更是在濱河造成了極大的恐慌滔吠,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,324評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件挠日,死亡現(xiàn)場(chǎng)離奇詭異疮绷,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)嚣潜,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,356評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門冬骚,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人懂算,你說我怎么就攤上這事只冻。” “怎么了计技?”我有些...
    開封第一講書人閱讀 162,328評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵喜德,是天一觀的道長。 經(jīng)常有香客問我垮媒,道長舍悯,這世上最難降的妖魔是什么航棱? 我笑而不...
    開封第一講書人閱讀 58,147評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮萌衬,結(jié)果婚禮上饮醇,老公的妹妹穿的比我還像新娘。我一直安慰自己秕豫,他們只是感情好朴艰,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,160評(píng)論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著混移,像睡著了一般祠墅。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上歌径,一...
    開封第一講書人閱讀 51,115評(píng)論 1 296
  • 那天饵隙,我揣著相機(jī)與錄音,去河邊找鬼沮脖。 笑死,一個(gè)胖子當(dāng)著我的面吹牛芯急,可吹牛的內(nèi)容都是我干的勺届。 我是一名探鬼主播,決...
    沈念sama閱讀 40,025評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼娶耍,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼免姿!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起榕酒,我...
    開封第一講書人閱讀 38,867評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤胚膊,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后想鹰,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體紊婉,經(jīng)...
    沈念sama閱讀 45,307評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,528評(píng)論 2 332
  • 正文 我和宋清朗相戀三年辑舷,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了喻犁。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,688評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡何缓,死狀恐怖肢础,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情碌廓,我是刑警寧澤传轰,帶...
    沈念sama閱讀 35,409評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站谷婆,受9級(jí)特大地震影響慨蛙,放射性物質(zhì)發(fā)生泄漏辽聊。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,001評(píng)論 3 325
  • 文/蒙蒙 一股淡、第九天 我趴在偏房一處隱蔽的房頂上張望身隐。 院中可真熱鬧,春花似錦唯灵、人聲如沸贾铝。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,657評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽垢揩。三九已至,卻和暖如春敛瓷,著一層夾襖步出監(jiān)牢的瞬間叁巨,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,811評(píng)論 1 268
  • 我被黑心中介騙來泰國打工呐籽, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留锋勺,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,685評(píng)論 2 368
  • 正文 我出身青樓狡蝶,卻偏偏與公主長得像庶橱,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子贪惹,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,573評(píng)論 2 353

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