1.JVM內(nèi)存管理深度剖析, GC算法與底層原理如此簡單

image.png

image.png

image.png

運(yùn)行時(shí)數(shù)據(jù)區(qū)域

image.png

JAVA方法運(yùn)行的內(nèi)存區(qū)域

image.png
  • 程序計(jì)數(shù)器
    較小的內(nèi)存空間,當(dāng)前線程執(zhí)行的字節(jié)碼的行號指示器;各線程之間獨(dú)立存儲(chǔ)品嚣,互不影響。
    程序計(jì)數(shù)器是一塊很小的內(nèi)存空間钧大,主要用來記錄各個(gè)線程執(zhí)行的字節(jié)碼的地址翰撑,例如,分支啊央、循環(huán)眶诈、跳轉(zhuǎn)、異常瓜饥、線程恢復(fù)等都依賴于計(jì)數(shù)器逝撬。
    由于 Java 是多線程語言,當(dāng)執(zhí)行的線程數(shù)量超過 CPU 核數(shù)時(shí)乓土,線程之間會(huì)根據(jù)時(shí)間片輪詢爭奪 CPU 資源宪潮。如果一個(gè)線程的時(shí)間片用完了,或者是其它原因?qū)е逻@個(gè)線程的 CPU 資源被提前搶奪趣苏,那么這個(gè)退出的線程就需要單獨(dú)的一個(gè)程序計(jì)數(shù)器狡相,來記錄下一條運(yùn)行的指令。
    程序計(jì)數(shù)器也是JVM中唯一不會(huì)OOM(OutOfMemory)的內(nèi)存區(qū)域
  • 虛擬機(jī)棧
    棧是什么樣的數(shù)據(jù)結(jié)構(gòu)食磕?先進(jìn)后出(FILO)的數(shù)據(jù)結(jié)構(gòu)尽棕,
    虛擬機(jī)棧在JVM運(yùn)行過程中存儲(chǔ)當(dāng)前線程運(yùn)行方法所需的數(shù)據(jù),指令彬伦、返回地址滔悉。
    Java 虛擬機(jī)棧是基于線程的伊诵。哪怕你只有一個(gè) main() 方法,也是以線程的方式運(yùn)行的回官。在線程的生命周期中曹宴,參與計(jì)算的數(shù)據(jù)會(huì)頻繁地入棧和出棧,棧的生命周期是和線程一樣的孙乖。
    棧里的每條數(shù)據(jù)浙炼,就是棧幀份氧。在每個(gè) Java 方法被調(diào)用的時(shí)候唯袄,都會(huì)創(chuàng)建一個(gè)棧幀,并入棧蜗帜。一旦完成相應(yīng)的調(diào)用恋拷,則出棧。所有的棧幀都出棧后厅缺,線程也就結(jié)束了蔬顾。
    每個(gè)棧幀,都包含四個(gè)區(qū)域:(局部變量表湘捎、操作數(shù)棧诀豁、動(dòng)態(tài)連接、返回地址)
    棧的大小缺省為1M窥妇,可用參數(shù) –Xss調(diào)整大小舷胜,例如-Xss256k
  1. 局部變量表:顧名思義就是局部變量的表,用于存放我們的局部變量的活翩。首先它是一個(gè)32位的長度烹骨,主要存放我們的Java的八大基礎(chǔ)數(shù)據(jù)類型,一般32位就可以存放下材泄,如果是64位的就使用高低位占用兩個(gè)也可以存放下沮焕,如果是局部的一些對象,比如我們的Object對象拉宗,我們只需要存放它的一個(gè)引用地址即可峦树。
  2. 操作數(shù)據(jù)棧:存放我們方法執(zhí)行的操作數(shù)的,它就是一個(gè)棧旦事,先進(jìn)后出的棧結(jié)構(gòu)魁巩,操作數(shù)棧,就是用來操作的族檬,操作的的元素可以是任意的java數(shù)據(jù)類型歪赢,所以我們知道一個(gè)方法剛剛開始的時(shí)候,這個(gè)方法的操作數(shù)棧就是空的单料,操作數(shù)棧運(yùn)行方法就是JVM一直運(yùn)行入棧/出棧的操作
  3. 動(dòng)態(tài)連接:Java語言特性多態(tài)(需要類運(yùn)行時(shí)才能確定具體的方法)埋凯。
  4. 返回地址:正常返回(調(diào)用程序計(jì)數(shù)器中的地址作為返回)点楼、異常的話(通過異常處理器表<非棧幀中的>來確定)

棧幀執(zhí)行對內(nèi)存區(qū)域的影響

image.png

本地(native)方法運(yùn)行的內(nèi)存區(qū)域

本地方法棧

image.png
  • 本地方法棧跟 Java 虛擬機(jī)棧的功能類似甩恼,Java 虛擬機(jī)棧用于管理 Java 函數(shù)的調(diào)用蟀瞧,而本地方法棧則用于管理本地方法的調(diào)用。但本地方法并不是用 Java 實(shí)現(xiàn)的条摸,而是由 C 語言實(shí)現(xiàn)的悦污。
    本地方法棧是和虛擬機(jī)棧非常相似的一個(gè)區(qū)域,它服務(wù)的對象是 native 方法钉蒲。你甚至可以認(rèn)為虛擬機(jī)棧和本地方法棧是同一個(gè)區(qū)域切端。
    虛擬機(jī)規(guī)范無強(qiáng)制規(guī)定,各版本虛擬機(jī)自由實(shí)現(xiàn) 顷啼,HotSpot直接把本地方法棧和虛擬機(jī)棧合二為一 踏枣。

線程共享的區(qū)域

image.png

方法區(qū)/永久代

很多開發(fā)者都習(xí)慣將方法區(qū)稱為“永久代”,其實(shí)這兩者并不是等價(jià)的钙蒙。

HotSpot 虛擬機(jī)使用永久代來實(shí)現(xiàn)方法區(qū)茵瀑,但在其它虛擬機(jī)中,例如躬厌,Oracle 的 JRockit马昨、IBM 的 J9 就不存在永久代一說。因此烤咧,方法區(qū)只是 JVM 中規(guī)范的一部分偏陪,可以說,在 HotSpot 虛擬機(jī)中煮嫌,設(shè)計(jì)人員使用了永久代來實(shí)現(xiàn)了 JVM 規(guī)范的方法區(qū)笛谦。

方法區(qū)主要是用來存放已被虛擬機(jī)加載的類相關(guān)信息,包括類信息昌阿、靜態(tài)變量饥脑、常量、運(yùn)行時(shí)常量池懦冰、字符串常量池灶轰。

JVM 在執(zhí)行某個(gè)類的時(shí)候,必須先加載刷钢。在加載類(加載笋颤、驗(yàn)證、準(zhǔn)備、解析伴澄、初始化)的時(shí)候赋除,JVM 會(huì)先加載 class 文件,而在 class 文件中除了有類的版本非凌、字段举农、方法和接口等描述信息外,還有一項(xiàng)信息是常量池 (Constant Pool Table)敞嗡,用于存放編譯期間生成的各種字面量和符號引用颁糟。

字面量包括字符串(String a=“b”)、基本類型的常量(final 修飾的變量)喉悴,符號引用則包括類和方法的全限定名(例如 String 這個(gè)類棱貌,它的全限定名就是 Java/lang/String)、字段的名稱和描述符以及方法的名稱和描述符粥惧。

而當(dāng)類加載到內(nèi)存中后键畴,JVM 就會(huì)將 class 文件常量池中的內(nèi)容存放到運(yùn)行時(shí)的常量池中;在解析階段突雪,JVM 會(huì)把符號引用替換為直接引用(對象的索引值)。

例如涡贱,類中的一個(gè)字符串常量在 class 文件中時(shí)咏删,存放在 class 文件常量池中的;在 JVM 加載完類之后问词,JVM 會(huì)將這個(gè)字符串常量放到運(yùn)行時(shí)常量池中督函,并在解析階段,指定該字符串對象的索引值激挪。運(yùn)行時(shí)常量池是全局共享的辰狡,多個(gè)類共用一個(gè)運(yùn)行時(shí)常量池,class 文件中常量池多個(gè)相同的字符串在運(yùn)行時(shí)常量池只會(huì)存在一份垄分。

方法區(qū)與堆空間類似宛篇,也是一個(gè)共享內(nèi)存區(qū),所以方法區(qū)是線程共享的薄湿。假如兩個(gè)線程都試圖訪問方法區(qū)中的同一個(gè)類信息叫倍,而這個(gè)類還沒有裝入 JVM,那么此時(shí)就只允許一個(gè)線程去加載它豺瘤,另一個(gè)線程必須等待吆倦。在 HotSpot 虛擬機(jī)、Java7 版本中已經(jīng)將永久代的靜態(tài)變量和運(yùn)行時(shí)常量池轉(zhuǎn)移到了堆中坐求,其余部分則存儲(chǔ)在 JVM 的非堆內(nèi)存中蚕泽,而 Java8 版本已經(jīng)將方法區(qū)中實(shí)現(xiàn)的永久代去掉了,并用元空間(class metadata)代替了之前的永久代桥嗤,并且元空間的存儲(chǔ)位置是本地

元空間大小參數(shù):

jdk1.7及以前(初始和最大值):-XX:PermSize须妻;-XX:MaxPermSize派任;

jdk1.8以后(初始和最大值):-XX:MetaspaceSize; -XX:MaxMetaspaceSize

jdk1.8以后大小就只受本機(jī)總內(nèi)存的限制(如果不設(shè)置參數(shù)的話)

JVM參數(shù)參考:<u>https://docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html</u>

Java8 為什么使用元空間替代永久代璧南,這樣做有什么好處呢掌逛?

官方給出的解釋是:

移除永久代是為了融合 HotSpot JVM 與 JRockit VM 而做出的努力,因?yàn)?JRockit 沒有永久代司倚,所以不需要配置永久代豆混。

永久代內(nèi)存經(jīng)常不夠用或發(fā)生內(nèi)存溢出,拋出異常 java.lang.OutOfMemoryError: PermGen动知。這是因?yàn)樵?JDK1.7 版本中皿伺,指定的 PermGen 區(qū)大小為 8M,由于 PermGen 中類的元數(shù)據(jù)信息在每次 FullGC 的時(shí)候都可能被收集盒粮,回收率都偏低鸵鸥,成績很難令人滿意;還有丹皱,為 PermGen 分配多大的空間很難確定妒穴,PermSize 的大小依賴于很多因素,比如摊崭,JVM 加載的 class 總數(shù)讼油、常量池的大小和方法的大小等。

深入辨析堆和棧

image.png

  • 堆是 JVM 上最大的內(nèi)存區(qū)域呢簸,我們申請的幾乎所有的對象矮台,都是在這里存儲(chǔ)的。我們常說的垃圾回收根时,操作的對象就是堆瘦赫。
    堆空間一般是程序啟動(dòng)時(shí),就申請了蛤迎,但是并不一定會(huì)全部使用确虱。
    隨著對象的頻繁創(chuàng)建,堆空間占用的越來越多忘苛,就需要不定期的對不再使用的對象進(jìn)行回收蝉娜。這個(gè)在 Java 中,就叫作 GC(Garbage Collection)扎唾。
    那一個(gè)對象創(chuàng)建的時(shí)候召川,到底是在堆上分配,還是在棧上分配呢胸遇?這和兩個(gè)方面有關(guān):對象的類型和在 Java 類中存在的位置荧呐。
    Java 的對象可以分為基本數(shù)據(jù)類型和普通對象。
    對于普通對象來說,JVM 會(huì)首先在堆上創(chuàng)建對象倍阐,然后在其他地方使用的其實(shí)是它的引用概疆。比如,把這個(gè)引用保存在虛擬機(jī)棧的局部變量表中峰搪。
    對于基本數(shù)據(jù)類型來說(byte岔冀、short、int概耻、long使套、float、double鞠柄、char)侦高,有兩種情況。當(dāng)你在方法體內(nèi)聲明了基本數(shù)據(jù)類型的對象厌杜,它就會(huì)在棧上直接分配奉呛。其他情況藤滥,都是在堆上分配竭恬。

  • 堆大小參數(shù)
    -Xms:堆的最小值;
    -Xmx:堆的最大值境析;
    -Xmn:新生代的大心琶取馁痴;
    -XX:NewSize;新生代最小值肺孤;
    -XX:MaxNewSize:新生代最大值;
    例如- Xmx256m

  • 直接內(nèi)存
    不是虛擬機(jī)運(yùn)行時(shí)數(shù)據(jù)區(qū)的一部分济欢,也不是java虛擬機(jī)規(guī)范中定義的內(nèi)存區(qū)域赠堵;如果使用了NIO,這塊區(qū)域會(huì)被頻繁使用,在java堆內(nèi)可以用directByteBuffer對象直接引用并操作法褥;
    這塊內(nèi)存不受java堆大小限制茫叭,但受本機(jī)總內(nèi)存的限制,可以通過-XX:MaxDirectMemorySize來設(shè)置(默認(rèn)與堆內(nèi)存最大值一樣)半等,所以也會(huì)出現(xiàn)OOM異常揍愁。

內(nèi)存溢出類型

  • 棧溢出
    參數(shù):-Xss1m, 具體默認(rèn)值需要查看官網(wǎng):https://docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html#BABHDABI

    image.png

    HotSpot版本中棧的大小是固定的杀饵,是不支持拓展的莽囤。
    java.lang.StackOverflowError 一般的方法調(diào)用是很難出現(xiàn)的,如果出現(xiàn)了可能會(huì)是無限遞歸切距。
    虛擬機(jī)棧帶給我們的啟示:方法的執(zhí)行因?yàn)橐虬蓷E朽缎,所以天生要比實(shí)現(xiàn)同樣功能的循環(huán)慢,所以樹的遍歷算法中:遞歸和非遞歸(循環(huán)來實(shí)現(xiàn))都有存在的意義。遞歸代碼簡潔话肖,非遞歸代碼復(fù)雜但是速度較快北秽。
    OutOfMemoryError:不斷建立線程,JVM申請棧內(nèi)存最筒,機(jī)器沒有足夠的內(nèi)存贺氓。(一般演示不出,演示出來機(jī)器也死了)

  • 堆溢出
    申請內(nèi)存空間,超出最大堆內(nèi)存空間床蜘。
    如果是內(nèi)存溢出辙培,則通過 調(diào)大 -Xms,-Xmx參數(shù)悄泥。
    如果不是內(nèi)存泄漏虏冻,就是說內(nèi)存中的對象卻是都是必須存活的,那么久應(yīng)該檢查JVM的堆參數(shù)設(shè)置弹囚,與機(jī)器的內(nèi)存對比厨相,看是否還有可以調(diào)整的空間,再從代碼上檢查是否存在某些對象生命周期過長鸥鹉、持有狀態(tài)時(shí)間過長蛮穿、存儲(chǔ)結(jié)構(gòu)設(shè)計(jì)不合理等情況,盡量減少程序運(yùn)行時(shí)的內(nèi)存消耗毁渗。

  • 方法區(qū)溢出
    1)運(yùn)行時(shí)常量池溢出
    2)方法區(qū)中保存的Class對象沒有被及時(shí)回收掉或者Class信息占用的內(nèi)存超過了我們配置践磅。

注意Class要被回收,條件比較苛刻(僅僅是可以灸异,不代表必然府适,因?yàn)檫€有一些參數(shù)可以進(jìn)行控制):

1、 該類所有的實(shí)例都已經(jīng)被回收肺樟,也就是堆中不存在該類的任何實(shí)例檐春。

2、 加載該類的ClassLoader已經(jīng)被回收么伯。

3疟暖、 該類對應(yīng)的java.lang.Class對象沒有在任何地方被引用,無法在任何地方通過反射訪問該類的方法田柔。

image.png

代碼示例:

cglib是一個(gè)強(qiáng)大的俐巴,高性能,高質(zhì)量的Code生成類庫硬爆,它可以在運(yùn)行期擴(kuò)展Java類與實(shí)現(xiàn)Java接口欣舵。

CGLIB包的底層是通過使用一個(gè)小而快的字節(jié)碼處理框架ASM,來轉(zhuǎn)換字節(jié)碼并生成新的類摆屯。除了CGLIB包邻遏,腳本語言例如Groovy和BeanShell糠亩,也是使用ASM來生成java的字節(jié)碼。當(dāng)然不鼓勵(lì)直接使用ASM准验,因?yàn)樗竽惚仨殞VM內(nèi)部結(jié)構(gòu)包括class文件的格式和指令集都很熟悉赎线。

  • 本機(jī)直接內(nèi)存溢出
    直接內(nèi)存的容量可以通過MaxDirectMemorySize來設(shè)置(默認(rèn)與堆內(nèi)存最大值一樣),所以也會(huì)出現(xiàn)OOM異常糊饱;
    由直接內(nèi)存導(dǎo)致的內(nèi)存溢出垂寥,一個(gè)比較明顯的特征是在HeapDump文件中不會(huì)看見有什么明顯的異常情況,如果發(fā)生了OOM另锋,同時(shí)Dump文件很小滞项,可以考慮重點(diǎn)排查下直接內(nèi)存方面的原因。

虛擬機(jī)優(yōu)化技術(shù)

image.png
  • 方法內(nèi)聯(lián)的優(yōu)化行為夭坪,就是把目標(biāo)方法的代碼原封不動(dòng)的“復(fù)制”到調(diào)用的方法中文判,避免真實(shí)的方法調(diào)用而已。


    image.png
  • 在一般的模型中室梅,兩個(gè)不同的棧幀的內(nèi)存區(qū)域是獨(dú)立的戏仓,但是大部分的JVM在實(shí)現(xiàn)中會(huì)進(jìn)行一些優(yōu)化,使得兩個(gè)棧幀出現(xiàn)一部分重疊亡鼠。(主要體現(xiàn)在方法中有參數(shù)傳遞的情況)赏殃,讓下面棧幀的操作數(shù)棧和上面棧幀的部分局部變量重疊在一起,這樣做不但節(jié)約了一部分空間间涵,更加重要的是在進(jìn)行方法調(diào)用時(shí)就可以直接公用一部分?jǐn)?shù)據(jù)仁热,無需進(jìn)行額外的參數(shù)復(fù)制傳遞了。

從底層深入理解運(yùn)行時(shí)數(shù)據(jù)區(qū)

開啟HSDB工具
Jdk1.8啟動(dòng)JHSDB的時(shí)候必須將sawindbg.dll復(fù)制到對應(yīng)目錄的jre下


image.png

C:\Program Files\Java\jdk1.8.0_101\lib
執(zhí)行 java -cp .\sa-jdi.jar sun.jvm.hotspot.HSDB


image.png

當(dāng)我們通過 Java 運(yùn)行以上代碼時(shí)勾哩,JVM 的整個(gè)處理過程如下:

  1. JVM 向操作系統(tǒng)申請內(nèi)存抗蠢,JVM 第一步就是通過配置參數(shù)或者默認(rèn)配置參數(shù)向操作系統(tǒng)申請內(nèi)存空間。

  2. JVM 獲得內(nèi)存空間后思劳,會(huì)根據(jù)配置參數(shù)分配堆物蝙、棧以及方法區(qū)的內(nèi)存大小。

  3. 完成上一個(gè)步驟后敢艰, JVM 首先會(huì)執(zhí)行構(gòu)造器,編譯器會(huì)在.java 文件被編譯成.class 文件時(shí)册赛,收集所有類的初始化代碼钠导,包括靜態(tài)變量賦值語句、靜態(tài)代碼塊森瘪、靜態(tài)方法牡属,靜態(tài)變量和常量放入方法區(qū)

  4. 執(zhí)行方法。啟動(dòng) main 線程扼睬,執(zhí)行 main 方法逮栅,開始執(zhí)行第一行代碼悴势。此時(shí)堆內(nèi)存中會(huì)創(chuàng)建一個(gè) Teacher 對象,對象引用 student 就存放在棧中措伐。

執(zhí)行其他方法時(shí)特纤,具體的操作:棧幀執(zhí)行對內(nèi)存區(qū)域的影響。<u>棧幀執(zhí)行對內(nèi)存區(qū)域的影響</u>

image.png

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末侥加,一起剝皮案震驚了整個(gè)濱河市捧存,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌担败,老刑警劉巖昔穴,帶你破解...
    沈念sama閱讀 211,817評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異提前,居然都是意外死亡吗货,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,329評論 3 385
  • 文/潘曉璐 我一進(jìn)店門狈网,熙熙樓的掌柜王于貴愁眉苦臉地迎上來宙搬,“玉大人,你說我怎么就攤上這事孙援『τ伲” “怎么了?”我有些...
    開封第一講書人閱讀 157,354評論 0 348
  • 文/不壞的土叔 我叫張陵拓售,是天一觀的道長窥摄。 經(jīng)常有香客問我,道長础淤,這世上最難降的妖魔是什么崭放? 我笑而不...
    開封第一講書人閱讀 56,498評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮鸽凶,結(jié)果婚禮上币砂,老公的妹妹穿的比我還像新娘。我一直安慰自己玻侥,他們只是感情好决摧,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,600評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著凑兰,像睡著了一般掌桩。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上姑食,一...
    開封第一講書人閱讀 49,829評論 1 290
  • 那天波岛,我揣著相機(jī)與錄音,去河邊找鬼音半。 笑死则拷,一個(gè)胖子當(dāng)著我的面吹牛贡蓖,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播煌茬,決...
    沈念sama閱讀 38,979評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼斥铺,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了宣旱?” 一聲冷哼從身側(cè)響起仅父,我...
    開封第一講書人閱讀 37,722評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎浑吟,沒想到半個(gè)月后笙纤,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,189評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡组力,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,519評論 2 327
  • 正文 我和宋清朗相戀三年省容,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片燎字。...
    茶點(diǎn)故事閱讀 38,654評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡腥椒,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出候衍,到底是詐尸還是另有隱情笼蛛,我是刑警寧澤,帶...
    沈念sama閱讀 34,329評論 4 330
  • 正文 年R本政府宣布蛉鹿,位于F島的核電站滨砍,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏妖异。R本人自食惡果不足惜惋戏,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,940評論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望他膳。 院中可真熱鬧响逢,春花似錦、人聲如沸棕孙。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,762評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蟀俊。三九已至分歇,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間欧漱,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,993評論 1 266
  • 我被黑心中介騙來泰國打工葬燎, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留误甚,地道東北人缚甩。 一個(gè)月前我還...
    沈念sama閱讀 46,382評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像窑邦,于是被迫代替她去往敵國和親擅威。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,543評論 2 349