Python基礎(chǔ)30-面向?qū)ο?內(nèi)存管理機(jī)制-引用計(jì)數(shù)/垃圾回收/循環(huán)引用/弱引用)

1 對(duì)象存儲(chǔ)

  1. 在Python中萬(wàn)物皆對(duì)象
不存在基本數(shù)據(jù)類型蝙茶,`0,  1.2,  True, False, "abc"`等隆夯,這些全都是對(duì)象
  1. 所有對(duì)象, 都會(huì)在內(nèi)存中開辟一塊空間進(jìn)行存儲(chǔ)
2.1 會(huì)根據(jù)不同的類型以及內(nèi)容, 開辟不同的空間大小進(jìn)行存儲(chǔ)
2.2 返回該空間的地址給外界接收(稱為"引用"), 用于后續(xù)對(duì)這個(gè)對(duì)象的操作
2.3 可通過(guò) id() 函數(shù)獲取內(nèi)存地址(10進(jìn)制)
2.4 通過(guò) hex() 函數(shù)可以查看對(duì)應(yīng)的16進(jìn)制地址
class Person:
    pass

p = Person()
print(p)
print(id(p))
print(hex(id(p)))

>>>> 打印結(jié)果

<__main__.Person object at 0x107030470>
4412605552
0x107030470
  1. 對(duì)于整數(shù)和短小的字符, Python會(huì)進(jìn)行緩存; 不會(huì)創(chuàng)建多個(gè)相同對(duì)象
此時(shí), 被多次賦值, 只會(huì)有多份引用
num1 = 2
num2 = 2
print(id(num1), id(num2))

>>>> 打印結(jié)果

4366584464 4366584464
  1. 容器對(duì)象, 存儲(chǔ)的其他對(duì)象, 僅僅是其他對(duì)象的引用, 并不是其他對(duì)象本身
4.1 比如字典, 列表, 元組這些"容器對(duì)象"
4.2 全局變量是由一個(gè)大字典進(jìn)行引用
4.3 可通過(guò) global() 查看

2 對(duì)象回收

2.1 引用計(jì)數(shù)器

2.1.1概念

  • 一個(gè)對(duì)象, 會(huì)記錄著自身被引用的個(gè)數(shù)
  • 每增加一個(gè)引用, 這個(gè)對(duì)象的引用計(jì)數(shù)會(huì)自動(dòng)+1
  • 每減少一個(gè)引用, 這個(gè)對(duì)象的引用計(jì)數(shù)會(huì)自動(dòng)-1

2.1.2 計(jì)數(shù)器變化常見(jiàn)場(chǎng)景

  • 引用計(jì)數(shù)+1場(chǎng)景
1厘肮、對(duì)象被創(chuàng)建
    p1 = Person()
2轴脐、對(duì)象被引用
    p2 = p1
3大咱、對(duì)象被作為參數(shù)碴巾,傳入到一個(gè)函數(shù)中
    log(p1)
    這里注意會(huì)+2, 因?yàn)閮?nèi)部有兩個(gè)屬性引用著這個(gè)參數(shù)
4、對(duì)象作為一個(gè)元素啤月,存儲(chǔ)在容器中
    l = [p1]
  • +1 情況3說(shuō)明:內(nèi)部有兩個(gè)屬性引用著這個(gè)參數(shù)
    Python2.x 下打印 :_globals__func_globals 引用該參數(shù)對(duì)象谎仲,計(jì)數(shù)+2
    Python3.x 下打又E怠:則只有一個(gè)_globals__引用該對(duì)象辙诞,同樣計(jì)數(shù)+2
import sys

class Person:
    pass

p_xxx = Person() # 1

print(sys.getrefcount(p_xxx))


def log(obj):
    print(sys.getrefcount(obj))

log(p_xxx)


# for attr in dir(log):
#     print(attr, getattr(log, attr))


>>>> 打印結(jié)果

2
4
  • 引用計(jì)數(shù)-1場(chǎng)景
1、對(duì)象的別名被顯式銷毀
    del p1
2祈搜、對(duì)象的別名被賦予新的對(duì)象
    p1 = 123
3夭问、一個(gè)對(duì)象離開它的作用域
    一個(gè)函數(shù)執(zhí)行完畢時(shí)
    內(nèi)部的局部變量關(guān)聯(lián)的對(duì)象, 它的引用計(jì)數(shù)就會(huì)-1
4捧杉、對(duì)象所在的容器被銷毀味抖,或從容器中刪除對(duì)象

2.1.3 查看引用計(jì)數(shù)

  • 注意計(jì)數(shù)器會(huì)>1灰粮,因?yàn)閷?duì)象在 getrefcount方法中被引用
import sys
sys.getrefcount(對(duì)象) 
import sys

class Person:
    pass

p1 = Person() # 1

print(sys.getrefcount(p1)) # 2

p2 = p1 # 2

print(sys.getrefcount(p1)) # 3

del p2 # 1
print(sys.getrefcount(p1)) # 2

del p1
# print(sys.getrefcount(p1)) #error熔脂,因?yàn)樯弦恍写a執(zhí)行類p1對(duì)象已經(jīng)銷毀

>>>> 打印結(jié)果

2
3
2

2.2 循環(huán)引用

  • 對(duì)象間互相引用柑肴,導(dǎo)致對(duì)象不能通過(guò)引用計(jì)數(shù)器進(jìn)行銷毀
# 循環(huán)引用
class Person:
    pass

class Dog:
    pass

p = Person() 
d = Dog()   

p.pet = d 
d.master = p
  • 使用 objgraph 模塊
  • objgraph.count() 可以查看, 垃圾回收器, 跟蹤的對(duì)象個(gè)數(shù)
# 正常情況
import objgraph

class Person:
    pass


class Dog:
    pass

p = Person()
d = Dog()

print(objgraph.count("Person"))
print(objgraph.count("Dog"))

# 刪除 p, d之后, 對(duì)應(yīng)的對(duì)象是否被釋放掉
del p
del d

print(objgraph.count("Person"))
print(objgraph.count("Dog"))

>>>> 打印結(jié)果

1
1
0
0

# 循環(huán)引用
import objgraph

class Person:
    pass


class Dog:
    pass

p = Person()
d = Dog()

print(objgraph.count("Person"))
print(objgraph.count("Dog"))

p.pet = d
d.master = p

# 刪除 p, d之后, 對(duì)應(yīng)的對(duì)象是否被釋放掉
del p
del d

print(objgraph.count("Person"))
print(objgraph.count("Dog"))

>>>> 打印結(jié)果

1
1
1
1

2.2 垃圾回收

2.2.1 主要作用

  • 從經(jīng)歷過(guò) 引用計(jì)數(shù)器機(jī)制 仍未被釋放的對(duì)象中, 找到 循環(huán)引用 對(duì)象, 并回收相關(guān)對(duì)象

2.2.2 垃圾回收底層機(jī)制

2.2.2.1 如何找到 循環(huán)引用 對(duì)象

  1. 收集所有的"容器對(duì)象", 通過(guò)一個(gè)雙向鏈表進(jìn)行引用
* 容器對(duì)象
    可以引用其他對(duì)象的對(duì)象
        列表
        元組
        字典
        自定義類對(duì)象
        ...
* 非容器對(duì)象
    不能引用其他對(duì)象的對(duì)象
        數(shù)值
        字符串
        布爾
        ...
    注意: 針對(duì)于這些非容器對(duì)象的內(nèi)存, 有其他的管理機(jī)制
  1. 針對(duì)于每一個(gè)"容器對(duì)象", 通過(guò)一個(gè)變量gc_refs來(lái)記錄當(dāng)前對(duì)應(yīng)的引用計(jì)數(shù)
  2. 對(duì)于每個(gè)"容器對(duì)象",找到它引用的"容器對(duì)象", 并將這個(gè)"容器對(duì)象"的引用計(jì)數(shù) -1
  3. 經(jīng)過(guò)步驟3之后, 如果一個(gè)"容器對(duì)象"的引用計(jì)數(shù)為0, 就代表這個(gè)對(duì)象可以被回收, 而它肯定是因?yàn)?循環(huán)引用"導(dǎo)致不能被回收(存活到現(xiàn)在)

2.2.2.2 如何提升查找"循環(huán)引用"的性能?

1 問(wèn)題:

  • 如果程序當(dāng)中創(chuàng)建了很多個(gè)對(duì)象, 而針對(duì)于每一個(gè)對(duì)象都要參與"檢測(cè)"過(guò)程; 則會(huì)非常的耗費(fèi)性能

2 假設(shè):

  • 基于這個(gè)問(wèn)題, 產(chǎn)生了一種假設(shè):
1. 越命大的對(duì)象, 越長(zhǎng)壽
2. 假設(shè)一個(gè)對(duì)象10次檢測(cè)都沒(méi)給它干掉, 就認(rèn)定這個(gè)對(duì)象一定很長(zhǎng)壽, 就減少這貨的"檢測(cè)頻率"

3 設(shè)計(jì)機(jī)制:

  • 分待回收 機(jī)制
1. 默認(rèn)一個(gè)對(duì)象被創(chuàng)建出來(lái)后, 屬于 0 代
2. 如果經(jīng)歷過(guò)這一代"垃圾回收"后, 依然存活, 則劃分到下一代
3. "垃圾回收"的周期順序?yàn)?    0代"垃圾回收"一定次數(shù), 會(huì)觸發(fā) 0代和1代回收
    1代"垃圾回收"一定次數(shù), 會(huì)觸發(fā)0代, 1代和2代回收

2.2.2.3 垃圾檢測(cè)時(shí)機(jī)

  • 垃圾回收器當(dāng)中, 新增的對(duì)象個(gè)數(shù)-消亡的對(duì)象個(gè)數(shù) , 達(dá)到一定的閾值時(shí), 才會(huì)觸發(fā), 垃圾檢測(cè)
  • 通過(guò) gc 模塊查看當(dāng)前垃圾回收機(jī)制促發(fā)條件及設(shè)置條件
import gc

# 獲取
print(gc.get_threshold())

>>>> 打印結(jié)果
(700, 10, 10) 
# 參數(shù)1秽荞,700扬跋;代表:新增的對(duì)象個(gè)數(shù)-消亡的對(duì)象個(gè)數(shù) == 700 時(shí)會(huì)促發(fā)垃圾檢測(cè)時(shí)機(jī)
# 參數(shù)2趁猴,10彪见;代表:當(dāng)?shù)?代對(duì)象檢測(cè)次數(shù)達(dá)到10次時(shí)候余指,會(huì)促發(fā)0代和1代對(duì)象的檢測(cè)
# 參數(shù)3酵镜,10淮韭;代表:當(dāng)?shù)?代對(duì)象檢測(cè)次數(shù)達(dá)到10次時(shí)候靠粪,會(huì)促發(fā)0代占键、1代和2代對(duì)象的檢測(cè)


# 設(shè)置
gc.set_threshold(200, 5, 5)
print(gc.get_threshold())

>>>> 打印結(jié)果
(200, 5, 5)

2.2.3 垃圾回收時(shí)機(jī)

2.2.3.1 自動(dòng)回收

  1. 觸發(fā)條件
* 開啟垃圾回收機(jī)制
* 且達(dá)到啟動(dòng)垃圾回收對(duì)應(yīng)的閾值
  1. 開啟垃圾回收機(jī)制
gc.enable()
    開啟垃圾回收機(jī)制(默認(rèn)開啟)
gc.disable()
    關(guān)閉垃圾回收機(jī)制
gc.isenabled()
    判定是否開啟
  1. 啟動(dòng)垃圾回收對(duì)應(yīng)的閾值
  • 垃圾回收器中, 新增的對(duì)象個(gè)數(shù)和釋放的對(duì)象個(gè)數(shù)之差到達(dá)某個(gè)閾值
查看方法
    gc.get_threshold()
        獲取自動(dòng)回收閾值
    gc.set_threshold()
        設(shè)置自動(dòng)回收閾值

# 自動(dòng)回收
import gc

gc.disable()
print(gc.isenabled())

gc.enable()

print(gc.isenabled())

print(gc.get_threshold())
gc.set_threshold(1000, 15, 5)

一般會(huì)將對(duì)應(yīng)的閾值設(shè)置成更大的值畔乙,這樣可以提高程序性能

2.2.3.2 手動(dòng)回收

  1. 觸發(fā)條件
  • 調(diào)用 gc 模塊的collection() 方法
gc.collect(generation=None)
"""
    collect([generation]) -> n
    
    With no arguments, run a full collection.  The optional argument
    may be an integer specifying which generation to collect.  A ValueError
    is raised if the generation number is invalid.
    
    The number of unreachable objects is returned.
    """
  • generation 參數(shù):如果為空時(shí),則表明全代回收钥庇;指定代數(shù)的話,則會(huì)檢測(cè)該代之前的所有對(duì)象皮服,如:generation = 2硫眯,則檢測(cè)0两入、1和2代的對(duì)象
  • 不管之前垃圾回收機(jī)制是否開啟敲才,調(diào)用 collection() 方法后都會(huì)執(zhí)行一次垃圾回收
  1. 通過(guò) objgraph 查看該類實(shí)例引用計(jì)數(shù)
import objgraph
class Person:
    pass

class Dog:
    pass

p = Person()
d = Dog()

print(objgraph.count("Person"))
print(objgraph.count("Dog"))

>>>> 打印結(jié)果
0
0
  1. 因循環(huán)引用情況剃氧,引用計(jì)數(shù)器處理不了
import objgraph

class Person:
    pass

class Dog:
    pass

p = Person()
d = Dog()

p.pet = d
d.master = p

del p
del d

print(objgraph.count("Person"))
print(objgraph.count("Dog"))

>>>> 打印結(jié)果
1
1
  1. 手動(dòng)促發(fā)垃圾回收朋鞍,處理循環(huán)引用對(duì)象
import objgraph
import gc

class Person:
    pass

class Dog:
    pass

p = Person()
d = Dog()

p.pet = d
d.master = p


del p
del d

gc.collect() #手動(dòng)觸發(fā)垃圾回收

print(objgraph.count("Person"))
print(objgraph.count("Dog"))

>>>> 打印結(jié)果
0
0
  1. 即使將垃圾回收機(jī)制關(guān)閉滥酥,調(diào)用gc.collect() 時(shí)候都會(huì)啟動(dòng)觸發(fā)垃圾回收畦幢,執(zhí)行完后并未自動(dòng)開啟
import objgraph
import gc

gc.disable() #手動(dòng)關(guān)閉垃圾回收

class Person:
    pass

class Dog:
    pass

p = Person()
d = Dog()

p.pet = d
d.master = p


del p
del d

gc.collect() #手動(dòng)啟動(dòng)垃圾回收

print(objgraph.count("Person"))
print(objgraph.count("Dog"))

print(gc.isenabled()) # 檢查關(guān)閉后是否自動(dòng)開啟

>>>> 打印結(jié)果
0
0
False

3 循環(huán)引用 - 版本兼容方案宇葱、弱引用打破循環(huán)引用

  1. 循環(huán)引用通過(guò)手動(dòng)啟動(dòng)垃圾回收機(jī)制進(jìn)行回收
import objgraph
import gc

# 1. 定義了兩個(gè)類
class Person:
    pass

class Dog:
    pass

# 2. 根據(jù)這兩個(gè)類, 創(chuàng)建出兩個(gè)實(shí)例對(duì)象
p = Person()
d = Dog()

# 3. 讓兩個(gè)實(shí)例對(duì)象之間互相引用, 造成循環(huán)引用
p.pet = d
d.master = p

# 4. 嘗試刪除可到達(dá)引用之后, 測(cè)試真實(shí)對(duì)象是否有被回收
del p
del d

# 5. 通過(guò)"引用計(jì)數(shù)機(jī)制"無(wú)法回收; 需要借助"垃圾回收機(jī)制"進(jìn)行回收
gc.collect()

print(objgraph.count("Person"))
print(objgraph.count("Dog"))

>>>> 打印結(jié)果
0
0
  1. 可以通過(guò)重寫類方法 __del__ 查看類實(shí)例被釋放時(shí)標(biāo)識(shí)
  • Python3.x 環(huán)境
import objgraph
import gc

class Person:
    def __del__(self):
        print("Person對(duì)象, 被釋放了")
    pass

class Dog:
    def __del__(self):
        print("Dog對(duì)象, 被釋放了")
    pass

p = Person()
d = Dog()

p.pet = d
d.master = p

del p
del d

gc.collect()

print(objgraph.count("Person"))
print(objgraph.count("Dog"))

>>>> 打印結(jié)果
Person對(duì)象, 被釋放了
Dog對(duì)象, 被釋放了
0
0
  • Python2.x 環(huán)境時(shí):
    如果循環(huán)引用對(duì)象任意一個(gè)類里面實(shí)現(xiàn)了__del__方法吗氏,都會(huì)導(dǎo)致垃圾回收機(jī)制無(wú)法正常運(yùn)行
    并且不會(huì)執(zhí)行__del__方法
import objgraph
import gc

class Person:
    def __del__(self):
        print("Person對(duì)象, 被釋放了")
    pass

class Dog:
    def __del__(self):
        print("Dog對(duì)象, 被釋放了")
    pass

p = Person()
d = Dog()

p.pet = d
d.master = p

del p
del d

gc.collect()

print(objgraph.count("Person"))
print(objgraph.count("Dog"))

>>>> 打印結(jié)果
1
1
  • Python2.x 中循環(huán)引用類都沒(méi)有重寫__del__時(shí),則垃圾回收機(jī)制正常
import objgraph
import gc

class Person:
    # def __del__(self):
    #     print("Person對(duì)象, 被釋放了")
    pass

class Dog:
    # def __del__(self):
    #     print("Dog對(duì)象, 被釋放了")
    pass

p = Person()
d = Dog()

p.pet = d
d.master = p

del p
del d

gc.collect()

print(objgraph.count("Person"))
print(objgraph.count("Dog"))

>>>> 打印結(jié)果
0
0

4 打破循環(huán)引用的方法

  1. 手動(dòng)強(qiáng)制將循環(huán)引用的屬性置 None膀哲。 p.pet = None
    Python2.x 環(huán)境
import objgraph
import gc

# 1. 定義了兩個(gè)類
class Person:
    def __del__(self):
        print("Person對(duì)象, 被釋放了")
    pass

class Dog:
    def __del__(self):
        print("Dog對(duì)象, 被釋放了")
    pass

p = Person()
d = Dog()

p.pet = d
d.master = p

p.pet = None #強(qiáng)制置 None
del p
del d

gc.collect()

print(objgraph.count("Person"))
print(objgraph.count("Dog"))

>>>> 打印結(jié)果
Dog對(duì)象, 被釋放了
Person對(duì)象, 被釋放了
0
0

  1. 通過(guò)弱引用方式打破循環(huán)引用
    Python2.x 環(huán)境
  • 導(dǎo)入 weakref 模塊
  • 一對(duì)一弱引用 d.master = weakref.ref(p)

import objgraph
import gc
import weakref

# 1. 定義了兩個(gè)類
class Person:
    def __del__(self):
        print("Person對(duì)象, 被釋放了")
    pass

class Dog:
    def __del__(self):
        print("Dog對(duì)象, 被釋放了")
    pass

p = Person()
d = Dog()

p.pet = d
d.master = weakref.ref(p)

del p
del d

gc.collect()

print(objgraph.count("Person"))
print(objgraph.count("Dog"))

>>>> 打印結(jié)果

Person對(duì)象, 被釋放了
Dog對(duì)象, 被釋放了
0
0
  • 弱引用一對(duì)多
# 單個(gè)寫法
p.pets = {"dog":  weakref.ref(d1), "cat":  weakref.ref(c1)}
或
字典形式
p.pets = weakref.WeakValueDictionary({"dog": d1, "cat": c1})

一般還有 如下方法
WeakKeyDictionary
WeakSet
···
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市蔼囊,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌酱酬,老刑警劉巖膳沽,帶你破解...
    沈念sama閱讀 216,692評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件挑社,死亡現(xiàn)場(chǎng)離奇詭異痛阻,居然都是意外死亡录平,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,482評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門啤斗,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)钮莲,“玉大人崔拥,你說(shuō)我怎么就攤上這事链瓦《㈣耄” “怎么了贴膘?”我有些...
    開封第一講書人閱讀 162,995評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵刑峡,是天一觀的道長(zhǎng)突梦。 經(jīng)常有香客問(wèn)我,道長(zhǎng)骚勘,這世上最難降的妖魔是什么俏讹? 我笑而不...
    開封第一講書人閱讀 58,223評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮殉疼,結(jié)果婚禮上瓢娜,老公的妹妹穿的比我還像新娘眠砾。我一直安慰自己褒颈,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,245評(píng)論 6 388
  • 文/花漫 我一把揭開白布刨疼。 她就那樣靜靜地躺著币狠,像睡著了一般漩绵。 火紅的嫁衣襯著肌膚如雪止吐。 梳的紋絲不亂的頭發(fā)上宝踪,一...
    開封第一講書人閱讀 51,208評(píng)論 1 299
  • 那天,我揣著相機(jī)與錄音碍扔,去河邊找鬼瘩燥。 笑死,一個(gè)胖子當(dāng)著我的面吹牛不同,可吹牛的內(nèi)容都是我干的厉膀。 我是一名探鬼主播,決...
    沈念sama閱讀 40,091評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼二拐,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼服鹅!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起百新,我...
    開封第一講書人閱讀 38,929評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體桩卵,經(jīng)...
    沈念sama閱讀 45,346評(píng)論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡辞州,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,570評(píng)論 2 333
  • 正文 我和宋清朗相戀三年岛杀,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,739評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 35,437評(píng)論 5 344
  • 正文 年R本政府宣布吞鸭,位于F島的核電站滩字,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏享钞。R本人自食惡果不足惜寝姿,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,037評(píng)論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望想邦。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,677評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)杏头。三九已至寓娩,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間饭冬,已是汗流浹背扰魂。 一陣腳步聲響...
    開封第一講書人閱讀 32,833評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工姻成, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留才睹,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,760評(píng)論 2 369
  • 正文 我出身青樓羞酗,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親马篮。 傳聞我的和親對(duì)象是個(gè)殘疾皇子滥崩,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,647評(píng)論 2 354

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