深入理解JVM(一)JVM內(nèi)存模型

? Java虛擬機(jī)在執(zhí)行Java程序的過(guò)程中會(huì)把它所管理的內(nèi)存劃分為若干個(gè)不同的數(shù)據(jù)區(qū)域罢缸,總共包括以下幾個(gè)運(yùn)行時(shí)數(shù)據(jù)區(qū)域。

1 、程序計(jì)數(shù)器(Program Counter Register)

程序計(jì)數(shù)器是一塊較小的內(nèi)存空間,它的作用:

1.1. 可以看做是當(dāng)前線程所執(zhí)行的字節(jié)碼的信號(hào)指示器。字節(jié)碼解釋器就是通過(guò)改變?cè)撚?jì)數(shù)器的值來(lái)選取下一條需要執(zhí)行的字節(jié)碼指令, 分支唁情、循環(huán)、跳轉(zhuǎn)、異常處理、線程恢復(fù)等基礎(chǔ)功能都需依賴計(jì)數(shù)器來(lái)完成。注:但是贾漏,如果當(dāng)前線程正在執(zhí)行的是一個(gè)本地方法隐圾,那么此時(shí)程序計(jì)數(shù)器為空伍掀。

1.2. 在多線程的情況下,程序計(jì)數(shù)器用于記錄當(dāng)前線程執(zhí)行的位置暇藏,從而當(dāng)線程被切換回來(lái)的時(shí)候能夠知道該線程上次運(yùn)行到哪兒了。

特點(diǎn):線程私有的盐碱, 生命周期隨著線程的創(chuàng)建而創(chuàng)建把兔,隨著線程的結(jié)束而死亡。 此內(nèi)存區(qū)域是唯一一個(gè)在 Java 虛擬機(jī)規(guī)范中沒有規(guī)定任何 OutOfMemoryError 情況的區(qū)域瓮顽。

2缕贡、Java 虛擬機(jī)棧(Java Virtual Machine Stack)

Java 虛擬機(jī)棧與程序計(jì)數(shù)器一樣剂跟,也是線程私有的送淆,其生命周期與線程相同为居。虛擬機(jī) 棧描述的是 Java 方法執(zhí)行的內(nèi)存模型:每個(gè)方法被執(zhí)行的時(shí)候都會(huì)同時(shí)創(chuàng)建一個(gè)棧幀(Stack Frame)用于存儲(chǔ)局部變量表蒙畴、操作數(shù)棧、動(dòng)態(tài)鏈接呜象、方法出口等信息膳凝。每一個(gè)方法被調(diào)用 直至執(zhí)行完成的過(guò)程就對(duì)應(yīng)著一個(gè)棧幀在虛擬機(jī)棧中從入棧到出棧的過(guò)程。

局部變量表存放了編譯期可知的各種基本數(shù)據(jù)類型(boolean董朝、byte鸠项、char、short子姜、int祟绊、 float、long哥捕、double)牧抽、對(duì)象引用(reference 類型)和 returnAddress 類型(指向了一條字 節(jié)碼指令的地址)。其中 64 位長(zhǎng)度的 long 和 double 會(huì)占用 2 個(gè)局部變量空間(Slot遥赚,一個(gè) 32 位)扬舒,其余數(shù)據(jù)類型只占用 1 個(gè)。局部變量表所需的空間在編譯期間完成分配凫佛,當(dāng)進(jìn)入一 個(gè)方法時(shí)讲坎,其需要在幀中分配多大的局部變量空間是確定的孕惜,方法運(yùn)行期間不會(huì)改變局部變 量表的大小。局部變量表的創(chuàng)建是在方法被執(zhí)行的時(shí)候晨炕,隨著棧幀的創(chuàng)建而創(chuàng)建衫画。而且,局部變量表的大小在編譯時(shí)期就確定下來(lái)了瓮栗,在創(chuàng)建的時(shí)候只需分配事先規(guī)定好的大小即可削罩。此外,在方法運(yùn)行的過(guò)程中局部變量表的大小是不會(huì)發(fā)生改變的费奸。

Java 虛擬機(jī)規(guī)范中對(duì)該區(qū)域規(guī)定了兩種異常情況:

2.1.? 如 線 程 請(qǐng) 求 的 深 度 大 于 虛 擬 機(jī) 所 允 許 的 深 度 弥激, 棧 溢 出 , 如 遞 歸 時(shí) 愿阐, 拋 出

StackOverflowError 異常微服。

2.2.? 虛擬機(jī)棧動(dòng)態(tài)擴(kuò)展無(wú)法申請(qǐng)到足夠的內(nèi)存時(shí),拋出 OutOfMemoryError 異常缨历。

當(dāng)方法傳遞參數(shù)時(shí)實(shí)際上是一個(gè)方法將自己棧幀中局部變量表的副本傳遞給另一個(gè)方法棧幀中的局 部變量表(注意是副本职辨,而不是其本身),不管數(shù)據(jù)類型是什么(基本類型戈二,引用類型)

3、本地方法棧(Native Method Stack)

Java 虛擬機(jī)可能會(huì)使用到傳統(tǒng)的棧來(lái)支持 native 方法(使用 Java 語(yǔ)言以外的其它語(yǔ)言 編寫的方法)的執(zhí)行喳资。線程私有的觉吭,如 Sun HotSpot 虛擬機(jī)直接把本地方法棧和虛擬機(jī)棧合 二為一。Java 虛擬機(jī)規(guī)范中對(duì)該區(qū)域規(guī)定了兩種異常情況:

3.1.如線程請(qǐng)求的深度大于虛擬機(jī)所允許的深度仆邓,拋出 StackOverflowError 異常鲜滩。

3.2.虛擬機(jī)棧動(dòng)態(tài)擴(kuò)展無(wú)法申請(qǐng)到足夠的內(nèi)存時(shí),拋出 OutOfMemoryError 異常节值。

4徙硅、Java 堆(Java Heap)

Java 堆是 Java 虛擬機(jī)管理內(nèi)存中最大的一塊,是所有線程共享的內(nèi)存區(qū)域搞疗,隨虛擬機(jī)的啟動(dòng)而創(chuàng)建嗓蘑。該區(qū)域唯一目的是存放對(duì)象實(shí)例,幾乎所有對(duì)象的實(shí)例都在堆里面分配匿乃。 Java 虛擬機(jī)規(guī)范規(guī)定桩皿,Java 堆可以出于物理上不連續(xù)的內(nèi)存空間中,只要邏輯上連續(xù)即可幢炸,如同磁盤空間一樣泄隔,既可以實(shí)現(xiàn)成固定大小,也可以是擴(kuò)展的宛徊,當(dāng)前主流虛擬機(jī)都是 按照擴(kuò)展來(lái)實(shí)現(xiàn)的(通過(guò)-Xmx 和-Xms 控制)佛嬉。

Java堆是垃圾收集器管理的主要區(qū)域逻澳,因此也叫"GC堆",細(xì)分一點(diǎn)可以分為新生代和老年代暖呕;再細(xì)致一點(diǎn)新生代可以分為Eden空間斜做、From Survivor空間、ToSurvivor空間缰揪。

Java 虛擬機(jī)規(guī)范中對(duì)該區(qū)域規(guī)定了 OutOfMemoryError 異常:如果堆中沒有 內(nèi)存完成實(shí)例分配陨享,并且堆無(wú)法再擴(kuò)展則拋出 OutOfMemoryError 異常。(當(dāng) Ol d 區(qū)被放滿的之后钝腺,進(jìn)行 Full GC抛姑,F(xiàn)ull GC 后,若 Survivor 及 old 區(qū)仍然無(wú)法存放 從 Eden 復(fù)制過(guò)來(lái)的部分對(duì)象艳狐,則出現(xiàn) OOM 錯(cuò)誤/或者直接存放大對(duì)象定硝、大數(shù)組,導(dǎo)致老年代空間不足)

5毫目、方法區(qū)(Method Area)

方法區(qū)與 Java 堆一樣蔬啡,是各個(gè)線程共享的內(nèi)存區(qū)域,用于存儲(chǔ)已被虛擬機(jī)加載的類信 息镀虐、常量箱蟆、靜態(tài)變量、即時(shí)編譯器編譯后的代碼等數(shù)據(jù)刮便。在 HotSpot 中用永久代來(lái)實(shí)現(xiàn)方法區(qū)空猜,而其他虛擬機(jī)(如 BEA JRockit、IBM J9 等)是不存在永久代的恨旱。

Java7 中已經(jīng)將運(yùn)行時(shí)常量池從永久代移除辈毯,在 Java 堆(Heap)中開辟了一塊區(qū)域存放運(yùn)行時(shí)常量池。而在 Java8 中搜贤,已經(jīng)徹底沒有了永久代谆沃,將方法區(qū)直接放在一個(gè)與堆不相連的本地內(nèi)存區(qū)域,這個(gè)區(qū)域被叫做元空間仪芒。

元空間的本質(zhì)和永久代類似唁影,都是對(duì) JVM 規(guī)范中方法區(qū)的實(shí)現(xiàn)。不過(guò)元空間與永久代 之間最大的區(qū)別在于:元空間并不在虛擬機(jī)中掂名,而是使用本地內(nèi)存夭咬。因此,默認(rèn)情況下铆隘,元 空間的大小僅受本地內(nèi)存限制卓舵,但可以通過(guò)以下參數(shù)來(lái)指定元空間的大小:-XX:MetaspaceSize膀钠,初始空間大小掏湾。-XX:MaxMetaspaceSize裹虫,最大空間,默認(rèn)是沒有 限制的融击。Java 虛擬機(jī)規(guī)范中對(duì)方法區(qū)規(guī)定了 OutOfMemoryError 異常: 如果方法區(qū)的內(nèi)存空間 不能滿足內(nèi)存分配請(qǐng)求筑公,那 Java 虛擬機(jī)將拋出一個(gè) OutOfMemoryError 異常。

6尊浪、運(yùn)行時(shí)常量池(Runtime Constant Pool)

運(yùn)行時(shí)常量池是方法區(qū)的一部分匣屡。線程共享。Class 文件中除了有類的版本拇涤、字段捣作、方 法、接口等信息外鹅士,還有一項(xiàng)信息是常量池券躁,用于存放編譯期生成的各種字面常量和符號(hào)引 用,這部分內(nèi)容在類加載后存放到方法區(qū)的常量池中掉盅。

static 修飾的靜態(tài)變量也存放在方法區(qū)中也拜,但不是在常量池中(不能修飾局部變量),不 能在一個(gè)方法內(nèi)部定義 static 變量(final 可以)趾痘,只能定義為成員變量慢哈。

當(dāng)這個(gè)類被Java虛擬機(jī)加載后,class文件中的常量就存放在方法區(qū)的運(yùn)行時(shí)常量池中永票。而且在運(yùn)行期間岸军,可以向常量池中添加新的常量。如:String類的intern()方法就能在運(yùn)行期間向常量池中添加字符串常量瓦侮。

當(dāng)運(yùn)行時(shí)常量池中的某些常量沒有被對(duì)象引用,同時(shí)也沒有被變量引用佣谐,那么就需要垃圾收集器回收肚吏。

Java 虛擬機(jī)規(guī)范中對(duì)該區(qū)域規(guī)定了 OutOfMemoryError 異常: 當(dāng)常量池?zé)o法申請(qǐng)到內(nèi) 存時(shí)拋出 OutOfMemoryError 異常。

7狭魂、直接內(nèi)存

直接內(nèi)存是除Java虛擬機(jī)之外的內(nèi)存罚攀,但也有可能被Java使用。

在NIO中引入了一種基于通道和緩沖的IO方式雌澄。它可以通過(guò)調(diào)用本地方法直接分配Java虛擬機(jī)之外的內(nèi)存斋泄,然后通過(guò)一個(gè)存儲(chǔ)在Java堆中的DirectByteBuffer對(duì)象直接操作該內(nèi)存,而無(wú)需先將外面內(nèi)存中的數(shù)據(jù)復(fù)制到堆中再操作镐牺,從而提升了數(shù)據(jù)操作的效率炫掐。

直接內(nèi)存的大小不受Java虛擬機(jī)控制,但既然是內(nèi)存睬涧,當(dāng)內(nèi)存不足時(shí)就會(huì)拋出OOM異常募胃。

8旗唁、棧幀

棧幀是用于支持虛擬機(jī)進(jìn)行方法調(diào)用和方法執(zhí)行的數(shù)據(jù)結(jié)構(gòu),它是虛擬機(jī)運(yùn)行時(shí)數(shù)據(jù)區(qū) 的虛擬機(jī)棧的棧元素痹束。棧幀存儲(chǔ)了方法的局部變量表检疫,操作數(shù)棧,動(dòng)態(tài)連接和方法返回地址 等信息祷嘶。第一個(gè)方法從調(diào)用開始到執(zhí)行完成屎媳,就對(duì)應(yīng)著一個(gè)棧幀在虛擬機(jī)棧中從入棧到出棧 的過(guò)程。在編譯代碼的時(shí)候论巍,棧幀中需要多大的局部變量表烛谊,多深的操作數(shù)棧都已經(jīng)完全確 定了,并且寫入到了方法表的 Code 屬性中环壤,因此一個(gè)棧幀需要分配多少內(nèi)存晒来,不會(huì)受到程 序運(yùn)行期變量數(shù)據(jù)的影響,而僅僅取決于具體虛擬機(jī)的實(shí)現(xiàn)郑现。一個(gè)線程中的方法調(diào)用鏈可能會(huì)很長(zhǎng)湃崩,很多方法都同時(shí)處理執(zhí)行狀態(tài)。對(duì)于執(zhí)行引擎來(lái) 講接箫,活動(dòng)線程中攒读,只有虛擬機(jī)棧頂?shù)臈攀怯行У模Q為當(dāng)前棧幀(Current Stack Frame)辛友,這個(gè)棧幀所關(guān)聯(lián)的方法稱為當(dāng)前方法(Current Method)薄扁。

8.1、局部變量表

局部標(biāo)量表是一組變量值的存儲(chǔ)空間废累,一個(gè)以字長(zhǎng)為單位邓梅,從 0 開始計(jì)數(shù)的數(shù)組,用于 存放方法參數(shù)和局部變量邑滨。變量槽 (Variable Slot)是局部變量表的最小單位日缨,沒有強(qiáng)制規(guī) 定大小為 32 位,雖然 32 位足夠存放大部分類型的數(shù)據(jù)掖看。一個(gè) Slot 可以存放 boolean匣距、 byte、char哎壳、short毅待、int、float归榕、reference 和 returnAddress 8 種類型尸红。其中 reference 表 示對(duì)一個(gè)對(duì)象實(shí)例的引用。returnAddress 則指向了一條字節(jié)碼指令的地址。 對(duì)于 64 位的 long 和 double 變量而言驶乾,虛擬機(jī)會(huì)為其分配兩個(gè)連續(xù)的 Slot 空間邑飒。虛擬機(jī)通過(guò)索引定位的方式使用局部變量表。之前我們知道级乐,局部變量表存放的是方法參數(shù)和局部變量疙咸。當(dāng)調(diào)用方法是非 static 方法時(shí),局部變量表中第 0 位索引的 Slot 默認(rèn)是用于傳遞方法所屬對(duì)象實(shí)例的引用风科,即“this”關(guān)鍵字指向的對(duì)象撒轮。分配完方法參數(shù)后,便會(huì) 依次分配方法內(nèi)部定義的局部變量贼穆。

為了節(jié)省棧幀空間题山,局部變量表中的 Slot 是可以重用的。當(dāng)離開了某些變量的作用域 之后故痊,這些變量對(duì)應(yīng)的 Slot 就可以交給其他變量使用顶瞳。

8.2、操作數(shù)棧

操作數(shù)棧被組織成一個(gè)以字長(zhǎng)為單位的數(shù)組愕秫。但不是通過(guò)索引來(lái)訪問慨菱,而是通過(guò)標(biāo)準(zhǔn)棧 操作--壓棧和出棧來(lái)訪問。方法執(zhí)行中進(jìn)行算術(shù)運(yùn)算或者是調(diào)用其他的方法進(jìn)行參數(shù)傳遞的 時(shí)候是通過(guò)操作數(shù)棧進(jìn)行的戴甩。

在概念模型中符喝,兩個(gè)棧幀是相互獨(dú)立的。但是大多數(shù)虛擬機(jī)的實(shí)現(xiàn)都會(huì)進(jìn)行優(yōu)化甜孤,令兩 個(gè)棧幀出現(xiàn)一部分重疊协饲。令下面的部分操作數(shù)棧與上面的局部變量表重疊在一塊,這樣在方 法調(diào)用的時(shí)候可以共用一部分?jǐn)?shù)據(jù)缴川,無(wú)需進(jìn)行額外的參數(shù)復(fù)制傳遞茉稠。

8.3、幀數(shù)據(jù)區(qū)

棧幀需要一些數(shù)據(jù)來(lái)支持常量池解析把夸、正常方法返回和異常處理等而线。在幀數(shù)據(jù)區(qū)中保存

著訪問常量池的指針,方便程序訪問常量池扎即。此外,當(dāng)函數(shù)返回或者出現(xiàn)異常時(shí)况凉,虛擬機(jī)必 須恢復(fù)調(diào)用者函數(shù)的棧幀谚鄙,并讓調(diào)用者函數(shù)繼續(xù)執(zhí)行下去。對(duì)于異常處理刁绒,虛擬機(jī)必須有一 個(gè)異常處理表闷营,方便在發(fā)生異常的時(shí)候找到處理異常的代碼,因此異常處理表也是幀數(shù)據(jù)區(qū) 中重要的一部分。

8.3.1 動(dòng)態(tài)連接

每個(gè)棧幀都包含一個(gè)指向運(yùn)行時(shí)常量池中該棧幀所屬方法的引用傻盟,持有這個(gè)引用是為了

支持方法調(diào)用過(guò)程中的動(dòng)態(tài)連接速蕊。符號(hào)引用一部分會(huì)在類加載階段或者第一次使用的時(shí)候就 轉(zhuǎn)化為直接引用,這種轉(zhuǎn)化成為靜態(tài)解析娘赴。另外一部分在每一次運(yùn)行期間轉(zhuǎn)化為直接引用规哲, 這部分稱為動(dòng)態(tài)連接。

8.3.2 方法返回地址

當(dāng)一個(gè)方法開始執(zhí)行后诽表,只有兩種方式可以退出這個(gè)方法唉锌。第一種是執(zhí)行引擎遇到任意 一個(gè)方法返回的字節(jié)碼指令,這時(shí)候可能會(huì)有返回值傳遞給上層的方法調(diào)用者竿奏。

另一種退出方式是袄简,在方法執(zhí)行過(guò)程中遇到了異常,并且這個(gè)異常沒有在方法體內(nèi)得到 處理泛啸。無(wú)論采用何種退出方式绿语,在方法退出之后,都需要返回到方法被調(diào)用的位置候址,程序才 能繼續(xù)執(zhí)行吕粹。

8.4 OutOfMemoryError

在 eclipse 中設(shè)置-Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError(堆最小 值、最大值設(shè)置成一樣為了避免自動(dòng)擴(kuò)展宗雇,輸出內(nèi)存溢出時(shí)信息)

Java 堆用于存儲(chǔ)對(duì)象實(shí)例昂芜,只要不斷創(chuàng)建對(duì)象,并且保證 GC Roots 到對(duì)象之間有可達(dá)路 徑來(lái)避免垃圾回收赔蒲,當(dāng)對(duì)象數(shù)量達(dá)到最大堆容量后就產(chǎn)生內(nèi)存溢出異常泌神。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市舞虱,隨后出現(xiàn)的幾起案子欢际,更是在濱河造成了極大的恐慌,老刑警劉巖矾兜,帶你破解...
    沈念sama閱讀 211,123評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件损趋,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡椅寺,警方通過(guò)查閱死者的電腦和手機(jī)浑槽,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)返帕,“玉大人桐玻,你說(shuō)我怎么就攤上這事【S” “怎么了镊靴?”我有些...
    開封第一講書人閱讀 156,723評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵铣卡,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我偏竟,道長(zhǎng)煮落,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,357評(píng)論 1 283
  • 正文 為了忘掉前任踊谋,我火速辦了婚禮蝉仇,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘褪子。我一直安慰自己量淌,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,412評(píng)論 5 384
  • 文/花漫 我一把揭開白布嫌褪。 她就那樣靜靜地躺著呀枢,像睡著了一般。 火紅的嫁衣襯著肌膚如雪笼痛。 梳的紋絲不亂的頭發(fā)上裙秋,一...
    開封第一講書人閱讀 49,760評(píng)論 1 289
  • 那天,我揣著相機(jī)與錄音缨伊,去河邊找鬼摘刑。 笑死,一個(gè)胖子當(dāng)著我的面吹牛刻坊,可吹牛的內(nèi)容都是我干的枷恕。 我是一名探鬼主播,決...
    沈念sama閱讀 38,904評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼谭胚,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼徐块!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起灾而,我...
    開封第一講書人閱讀 37,672評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤胡控,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后旁趟,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體昼激,經(jīng)...
    沈念sama閱讀 44,118評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,456評(píng)論 2 325
  • 正文 我和宋清朗相戀三年锡搜,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了橙困。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,599評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡耕餐,死狀恐怖凡傅,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情蛾方,我是刑警寧澤像捶,帶...
    沈念sama閱讀 34,264評(píng)論 4 328
  • 正文 年R本政府宣布,位于F島的核電站桩砰,受9級(jí)特大地震影響拓春,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜亚隅,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,857評(píng)論 3 312
  • 文/蒙蒙 一啄育、第九天 我趴在偏房一處隱蔽的房頂上張望旺聚。 院中可真熱鬧,春花似錦、人聲如沸企蹭。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)畔裕。三九已至,卻和暖如春酿联,著一層夾襖步出監(jiān)牢的瞬間终息,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工贞让, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留周崭,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,286評(píng)論 2 360
  • 正文 我出身青樓喳张,卻偏偏與公主長(zhǎng)得像续镇,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子销部,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,465評(píng)論 2 348

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