iOS開發(fā):retain企软、release庐扫、dealloc

一、Tagged Pointer細(xì)節(jié)探究

蘋果為了提高執(zhí)行效率和節(jié)省內(nèi)存,引入了Tagged Pointer的概念形庭,對(duì)于64位程序來說可以達(dá)到3倍的訪問速度和100多倍的創(chuàng)建銷毀的速度杰妓。支持Tagged Pointer的類型以某種方式創(chuàng)建后便是Tagged Pointer指針,這種特殊的指針包括了數(shù)據(jù)內(nèi)容和附加信息碘勉,訪問的時(shí)候可以通過指針地址解碼獲得巷挥。

objc源碼中定義了全部的支持Tagged Pointer的類型,常用的類型摘錄如下验靡,如NSString倍宾、NSNumberNSIndexPath胜嗓、NSDate高职、UIColorNSIndexSet等:

...// 60-bit payloads
OBJC_TAG_NSString          = 2, 
OBJC_TAG_NSNumber          = 3, 
OBJC_TAG_NSIndexPath       = 4, 
OBJC_TAG_NSManagedObjectID = 5, 
OBJC_TAG_NSDate            = 6,
...// 52-bit payloads
OBJC_TAG_UIColor           = 17,
OBJC_TAG_CGColor           = 18,
OBJC_TAG_NSIndexSet        = 19,
OBJC_TAG_NSMethodSignature = 20,

先來看如下代碼的打印結(jié)果:

NSString *str1 = @"abcd";
NSString *str2 = [[NSString alloc] initWithString:str1];
NSString *str3 = [[NSString alloc] initWithFormat:@"%@", str1];
NSString *str4 = [[NSString alloc] initWithFormat:@"%@-%@-%@", str1,str1,str1];
NSLog(@"str1=%@, ptr=%p, class=%@;", str1, str1, [str1 class]);
NSLog(@"str2=%@, ptr=%p, class=%@;", str2, str2, [str2 class]);
NSLog(@"str3=%@, ptr=%p, class=%@;", str3, str3, [str3 class]);
NSLog(@"str4=%@, ptr=%p, class=%@;", str4, str4, [str4 class]);

打印結(jié)果:

str1=abcd, ptr=0x1020fc9d0, class=__NSCFConstantString;
str2=abcd, ptr=0x1020fc9d0, class=__NSCFConstantString;
str3=abcd, ptr=0xa1e53d6849de69de, class=NSTaggedPointerString;
str4=abcd-abcd-abcd, ptr=0x283195de0, class=__NSCFString;
  • 打印結(jié)果中str3的真實(shí)類型為NSTaggedPointerString辞州。str1怔锌、str2的真實(shí)類型為__NSCFConstantStringstr4的真實(shí)類型為__NSCFString变过。通過打印superclass找到了他們之間的繼承關(guān)系埃元,其中NSTaggedPointerStringNSString的子類。
    NSString.png
  • 打印結(jié)果可以看出媚狰,是否支持Tagged Pointer跟創(chuàng)建的方式和初始化的內(nèi)容長(zhǎng)度等也有關(guān)系岛杀。

先從這里入口,如何判斷一個(gè)對(duì)象是不是支持Tagged Pointer?

static inline bool  _objc_isTaggedPointer(const void * _Nullable ptr){
    return ((uintptr_t)ptr & _OBJC_TAG_MASK) == _OBJC_TAG_MASK;
}

//而_OBJC_TAG_MASK的定義與架構(gòu)平臺(tái)相關(guān)崭孤,真機(jī)的_OBJC_TAG_MASK = (1UL<<63) 类嗤,也就是高1位是1就是Tagged Pointer指針。

#if __arm64__
#   define OBJC_SPLIT_TAGGED_POINTERS 1  //64位真機(jī)
#else
#   define OBJC_SPLIT_TAGGED_POINTERS 0
#endif

#if OBJC_SPLIT_TAGGED_POINTERS
#   define _OBJC_TAG_MASK (1UL<<63)   //真機(jī):指針最高位為1
#elif OBJC_MSB_TAGGED_POINTERS
#   define _OBJC_TAG_MASK (1UL<<63)
#else
#   define _OBJC_TAG_MASK 1UL
# endif

為了避免開發(fā)人員直接從指針地址上直接獲取到內(nèi)容辨宠,我們直接通過指針取地址獲取到的都是encode之后的遗锣,要想拿到真實(shí)的信息需要decode:

static inline void * _Nonnull _objc_encodeTaggedPointer(uintptr_t ptr){
    uintptr_t value = (objc_debug_taggedpointer_obfuscator ^ ptr);
#if OBJC_SPLIT_TAGGED_POINTERS
    if ((value & _OBJC_TAG_NO_OBFUSCATION_MASK) == _OBJC_TAG_NO_OBFUSCATION_MASK)
        return (void *)ptr;
    uintptr_t basicTag = (value >> _OBJC_TAG_INDEX_SHIFT) & _OBJC_TAG_INDEX_MASK;
    uintptr_t permutedTag = _objc_basicTagToObfuscatedTag(basicTag);
    value &= ~(_OBJC_TAG_INDEX_MASK << _OBJC_TAG_INDEX_SHIFT);
    value |= permutedTag << _OBJC_TAG_INDEX_SHIFT;
#endif
    return (void *)value;
}

static inline uintptr_t_objc_decodeTaggedPointer_noPermute(const void * _Nullable ptr){
    uintptr_t value = (uintptr_t)ptr;
#if OBJC_SPLIT_TAGGED_POINTERS
    if ((value & _OBJC_TAG_NO_OBFUSCATION_MASK) == _OBJC_TAG_NO_OBFUSCATION_MASK)
        return value;
#endif
    return value ^ objc_debug_taggedpointer_obfuscator;
}

encode的時(shí)候通過objc_debug_taggedpointer_obfuscator與指針地址按位異或,decodeobjc_debug_taggedpointer_obfuscator 按位異或encode之后的值嗤形。而objc_debug_taggedpointer_obfuscator則是在應(yīng)用啟動(dòng)時(shí)_read_images()->initializeTaggedPointerObfuscator()初始化的精偿。在按位異或中相同為0,不同為1派殷,如果objc_debug_taggedpointer_obfuscator的值為0encode/decode前后的值應(yīng)該相同还最。DisableTaggedPointerObfuscation==YES的時(shí)候初始化的objc_debug_taggedpointer_obfuscator=0,可以在scheme的環(huán)境變量中配置OBJC_DISABLE_TAG_OBFUSCATION==YES之后在調(diào)試更方便。
設(shè)置環(huán)境變量操作如下:

設(shè)置環(huán)境變量.png

設(shè)置之后再次打印如上數(shù)據(jù)毡惜,其中str3的打印結(jié)果發(fā)生變化:str3=abcd, ptr=0x8000003231b130a2, class=NSTaggedPointerString;接下來按照官方說的方式去還原一下數(shù)據(jù):
還原字符串過程.png

常用類型總結(jié):

變量 地址 二進(jìn)制地址 說明
[NSString stringWithFormat:@"abcd"] 0x8000003231b130a2 0B1-0000000000000000000000000110
0100011000110110001001100001-0100-010
最高位為1,最低3位2代表NSString類型,4-7位為4表示字符串長(zhǎng)度
[NSString stringWithFormat:@"abcdefg"] 0xb3b332b231b130ba 0B1-0110011101100110011001010110
0100011000110110001001100001-0111-010
最高位為1,最低3位2代表NSString類型斯撮,4-7位為7表示字符串長(zhǎng)度
[NSNumber numberWithChar:1] 0x8000000000000083 0B1-0000000000000000000000000000
0000000000000000000000000001-0000-011
最高位為1,最低3位3代表NSNumber類型经伙,4-7位為0表示char型
[NSNumber numberWithShort:3]] 0x800000000000018b 0B1-0000000000000000000000000000
0000000000000000000000000011-0001-011
最高位為1,最低3位3代表NSNumber類型,4-7位為1表示short型
[NSNumber numberWithInt:7] 0x8000000000000393 0B1-0000000000000000000000000000
0000000000000000000000000111-0010-011
最高位為1,最低3位3代表NSNumber類型,4-7位為2表示int型
[NSNumber numberWithLong:52] 0x8000000000001a1b 0B1-0000000000000000000000000000
0000000000000000000000110100-0011-011
最高位為1,最低3位3代表NSNumber類型帕膜,4-7位為3表示long型
[NSIndexPath indexPathWithIndex:5] 0x8000000000002874 0B1-0000000000000000000000000000
0000000000000000000001010000-1110-100
最高位為1,最低3位4代表NSIndexPath類型
[NSDate date] 0x969db1df206a00a6 0B1-0010110100111011011000111011
1110010000001101010000000001-0100-110
最高位為1,最低3位6代表NSDate類型

采用Tagged Pointer存儲(chǔ)的小對(duì)象枣氧,需要在類型、創(chuàng)建方式垮刹、內(nèi)容長(zhǎng)度等方面滿足要求达吞,簡(jiǎn)單老說就是數(shù)據(jù)內(nèi)容、標(biāo)識(shí)位和擴(kuò)展信息需要在2^64位中能存儲(chǔ)完整完整荒典。我們?cè)趯?shí)際開發(fā)中不應(yīng)該依賴這些細(xì)節(jié)酪劫,這些內(nèi)容不同平臺(tái)不一樣,而且可能會(huì)經(jīng)常改變寺董。

二覆糟、retain/release的流程梳理

先看retain:


retain核心流程梳理.png

retain核心流程梳理如下:

  • 1.首次進(jìn)入rootRetain(tryRetain, variant):參數(shù)tryRetain=falsevariant=FastOrMsgSend遮咖。
  • 2.如果是isTaggedPointer滩字,則直接return this;反之繼續(xù)3.
  • 3.variant=FastOrMsgSend,執(zhí)行objc_msgSend(this, @selector(retain)),繼續(xù)4御吞。
  • 4.二次進(jìn)入rootRetain(tryRetain, variant):參數(shù)tryRetain=false麦箍,variant=Fast
  • 5.如果isa.nonpointer==0陶珠,執(zhí)行sidetable_retain():引用計(jì)數(shù)全部全部存儲(chǔ)在sidetable中内列;直接根據(jù)當(dāng)前對(duì)象找到存儲(chǔ)該對(duì)象的table,然后找到原有的refcntStorage+=SIDE_TABLE_RC_ONE即可背率。
  • 6.如果isa.nonpointer==1话瞧,應(yīng)用計(jì)數(shù)存儲(chǔ)在isa.extra_rcsidetable中。引用計(jì)數(shù)+1會(huì)優(yōu)先添加到isa.extra_rc上寝姿。如果存滿了交排,則先保存一半RC_HALFextra_rc中,并標(biāo)記has_sidetable_rc=true已使用引用計(jì)數(shù)表饵筑,處理完isa后更新isa的數(shù)據(jù)埃篓。再將另一半RC_HALF追加到sidetable中,保存到side_table的流程與2同根资。
  • 7.retain的最后返回this指針架专。

源碼中release的核心流程objc_object::rootRelease(bool performDealloc, objc_object::RRVariant variant)中,源碼較多玄帕,這里梳理核心流程如下:
release核心流程梳理如下:

  • 1.首次進(jìn)入rootRelease(performDealloc, variant):參數(shù)performDealloc=true, variant= FastOrMsgSend部脚。
  • 2.如果是isTaggedPointer,則直接return false;反之繼續(xù)3裤纹。
  • 3.variant=FastOrMsgSend委刘,執(zhí)行objc_msgSend)(this, @selector(release)),繼續(xù)4。
  • 4.二次進(jìn)入rootRelease(performDealloc, variant):參數(shù)performDealloc=true, variant= Fast锡移。
  • 5.如果isa.nonpointer==0呕童,執(zhí)行sidetable_release():引用計(jì)數(shù)全部存在sidetable中;根據(jù)當(dāng)前的對(duì)象找到存儲(chǔ)該對(duì)象引用計(jì)數(shù)的table淆珊,然后找到原有的refcnt -= SIDE_TABLE_RC_ONE;即可夺饲。滿足dealloc條件的,繼續(xù)執(zhí)行dealloc流程施符。
  • 6.如果isa.nonpointer==1往声,應(yīng)用計(jì)數(shù)存儲(chǔ)在isa.extra_rcsidetable中。引用繼續(xù)-1會(huì)先從isa.extra_rc上減操刀。如果不夠減了烁挟,會(huì)進(jìn)入underflow流程7.
  • 7.如果該對(duì)象有has_sidetable_rc,執(zhí)行rootRelease_underflow流程骨坑,三次進(jìn)入rootRelease(performDealloc, variant):參數(shù)performDealloc=true, variant= Full撼嗓。
  • 8.執(zhí)行auto borrow = sidetable_subExtraRC_nolock(RC_HALF);也就是問sidetableRC_HALF,返回借到的數(shù)量和剩余的數(shù)量欢唾。
  • 9.如果借到了則將借到的數(shù)量-1保存到isa.extrac_rc中且警。如果sidetable中剩余為0則標(biāo)記isa.has_sidetable_rc=0,再存儲(chǔ)新的isa.bits的數(shù)據(jù)。處理存儲(chǔ)失敗的情況礁遣。
  • 10.如果沒有借到或者根本就沒有再sidetable中存儲(chǔ)則執(zhí)行dealloc相關(guān)流程斑芜。

小結(jié):如果是Tagged Pointer小對(duì)象,沒有占用堆空間分配內(nèi)存祟霍,無需引用計(jì)數(shù)的管理杏头,小對(duì)象的釋放隨著棧空間的回收而釋放沸呐。常規(guī)對(duì)象醇王,先判斷有沒開啟isa優(yōu)化(isa.nonpointer==0),沒有開啟則對(duì)象的引用計(jì)數(shù)都存儲(chǔ)在sidetable中崭添,無論retain還是release都操作的是sidetable中的計(jì)數(shù)+1寓娩,-1,如果是release,則當(dāng)計(jì)數(shù)為0的時(shí)候執(zhí)行dealloc操作呼渣。如果開啟了isa優(yōu)化(isa.nonpointer==1),則對(duì)象的引用計(jì)數(shù)存儲(chǔ)在isa.extra_rc和sidetable中棘伴,優(yōu)先操作isa.extra_rcretain操作isa.extra_rc++屁置,當(dāng)isa.extra_rc中存滿255個(gè)后焊夸,就會(huì)分一半(1<<7)到sidetable中,并在isa中標(biāo)記isa.has_sidetable_rc=1缰犁。而release操作isa.extra_rc--淳地,當(dāng)isa.extra_rc中不夠減了怖糊,則會(huì)從sidetable中嘗試借1<<7個(gè)帅容,如果sidetable中被借了之后沒有了會(huì)設(shè)置isa.has_sidetable_rc=0颇象,借到的數(shù)據(jù)會(huì)加到isa.extra_rc中,方便后續(xù)使用并徘。如果沒有借到則執(zhí)行dealloc操作遣钳。

三、dealloc流程梳理

先看看底層objc_object::rootDealloc函數(shù):

inline void objc_object::rootDealloc(){
    if (isTaggedPointer()) return;  // fixme necessary?

    if (fastpath(isa.nonpointer                     &&
                 !isa.weakly_referenced             &&
                 !isa.has_assoc                     &&
#if ISA_HAS_CXX_DTOR_BIT
                 !isa.has_cxx_dtor                  &&
#else
                 !isa.getClass(false)->hasCxxDtor() &&
#endif
                 !isa.has_sidetable_rc)){
        assert(!sidetable_present());
        free(this);
    } 
    else {
        object_dispose((id)this);
    }
}

從這里可以看出如果一個(gè)對(duì)象是isTaggedPointer麦乞,那么這里什么事情都不做蕴茴。然后再判斷是否有開啟isa優(yōu)化、是否沒有被弱引用姐直、是否沒有關(guān)聯(lián)對(duì)象倦淀、是否沒有C++構(gòu)造/析構(gòu)函數(shù)、是否在sidetable中沒有引用計(jì)數(shù)了声畏,如果這些都是是撞叽,則直接調(diào)用底層free(this)回收內(nèi)存;反之則調(diào)用object_dispose(this)插龄。

接著進(jìn)入object_dispose函數(shù):

id object_dispose(id obj){
    if (!obj) return nil;
    objc_destructInstance(obj);    
    free(obj);
    return nil;
}

先執(zhí)行objc_destructInstance(obj)愿棋,再執(zhí)行free(obj)。結(jié)合上下文推測(cè)objc_destructInstance()應(yīng)該是處理弱引用表均牢、關(guān)聯(lián)對(duì)象表糠雨、引用計(jì)數(shù)表相關(guān)的問題的。

void *objc_destructInstance(id obj) {
    if (obj) {
        // Read all of the flags at once for performance.
        bool cxx = obj->hasCxxDtor();
        bool assoc = obj->hasAssociatedObjects();

        // This order is important.
        if (cxx) object_cxxDestruct(obj);
        if (assoc) _object_remove_assocations(obj, /*deallocating*/true);
        obj->clearDeallocating();
    }
    return obj;
}

objc_destructInstance函數(shù)中徘跪,做了三個(gè)事情:

  • 1甘邀、如果有c++析構(gòu)方法,則調(diào)用object_cxxDestruct(obj),內(nèi)部繼續(xù)調(diào)用object_cxxDestructFromClass()方法垮庐,最終會(huì)從子類到父類依次調(diào)用析構(gòu)函數(shù)(如果存在的話)松邪,具體調(diào)用析構(gòu)函數(shù)做什么,還需要進(jìn)一步探究。
  • 2.如果有關(guān)聯(lián)對(duì)象突硝,則調(diào)用_object_remove_assocations(obj, true)测摔,將該對(duì)象相關(guān)的關(guān)聯(lián)記錄擦除,同時(shí)如果關(guān)聯(lián)對(duì)象存在且引用計(jì)數(shù)策略是OBJC_ASSOCIATION_SETTER_RETAIN解恰,則像改對(duì)象發(fā)送objc_release(_value)消息锋八。
  • 3.調(diào)用obj->clearDeallocating()函數(shù),進(jìn)行弱引用對(duì)象护盈、引用計(jì)數(shù)相關(guān)的處理:如果沒有開啟isa.nonpointer挟纱,則調(diào)用sidetable_clearDeallocating()。如果該對(duì)象被弱引用或者再sidetable中存儲(chǔ)了引用計(jì)數(shù)則調(diào)用clearDeallocating_slow()腐宋。
sidetable_clearDeallocating()和clearDeallocating_slow()做的事情是一致的,核心代碼如下:
//3.1
void objc_object::sidetable_clearDeallocating(){
    SideTable& table = SideTables()[this];
    RefcountMap::iterator it = table.refcnts.find(this);
    if (it != table.refcnts.end()) {
        if (it->second & SIDE_TABLE_WEAKLY_REFERENCED) {
            weak_clear_no_lock(&table.weak_table, (id)this);
        }
        table.refcnts.erase(it);
    }
}
//3.2
NEVER_INLINE void objc_object::clearDeallocating_slow(){
    SideTable& table = SideTables()[this];
    if (isa.weakly_referenced) {
        weak_clear_no_lock(&table.weak_table, (id)this);
    }
    if (isa.has_sidetable_rc) {
        table.refcnts.erase(this);
    }
}
  • 4.weak_clear_no_lock進(jìn)行弱引用關(guān)系的處理:相關(guān)細(xì)節(jié)標(biāo)記在如下代碼中
void weak_clear_no_lock(weak_table_t *weak_table, id referent_id) {
    objc_object *referent = (objc_object *)referent_id;  //當(dāng)前對(duì)象referent
    weak_entry_t *entry = weak_entry_for_referent(weak_table, referent);//從weak_table取出entry
    if (entry == nil) {
        return;//如果weak_table中沒有紊服,則直接return
    }

   
    weak_referrer_t *referrers;//weak指針列表檀轨,List結(jié)構(gòu)
    size_t count;//weak指針的數(shù)量
    
    if (entry->out_of_line()) {
        referrers = entry->referrers;
        count = TABLE_SIZE(entry);
    } 
    else {
        referrers = entry->inline_referrers;
        count = WEAK_INLINE_COUNT;
    }
    
    //一次遍歷weak指針
    for (size_t i = 0; i < count; ++i) {
        objc_object **referrer = referrers[i];
        if (referrer) {
            if (*referrer == referent) {
                //如果weak指針指向的是自己,則將weak指針置空欺嗤,這也是為啥weak指針在對(duì)象釋放后被自動(dòng)置空的真正原因参萄。
                *referrer = nil;
            }
            else if (*referrer) {
                //weak指針存在entry. referrers中,但是weak指針并不指向自己:異常情況<灞6锟妗!處理
                objc_weak_error();
            }
        }
    }
    weak_entry_remove(weak_table, entry);//從weak_table表中移除該entry吆玖。
}
  • 5.table.refcnts.erase()進(jìn)行引用計(jì)數(shù)的處理筒溃。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市沾乘,隨后出現(xiàn)的幾起案子怜奖,更是在濱河造成了極大的恐慌,老刑警劉巖翅阵,帶你破解...
    沈念sama閱讀 219,039評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件歪玲,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡怎顾,警方通過查閱死者的電腦和手機(jī)读慎,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來槐雾,“玉大人夭委,你說我怎么就攤上這事∧记浚” “怎么了株灸?”我有些...
    開封第一講書人閱讀 165,417評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)擎值。 經(jīng)常有香客問我慌烧,道長(zhǎng),這世上最難降的妖魔是什么鸠儿? 我笑而不...
    開封第一講書人閱讀 58,868評(píng)論 1 295
  • 正文 為了忘掉前任屹蚊,我火速辦了婚禮,結(jié)果婚禮上进每,老公的妹妹穿的比我還像新娘汹粤。我一直安慰自己,他們只是感情好田晚,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,892評(píng)論 6 392
  • 文/花漫 我一把揭開白布嘱兼。 她就那樣靜靜地躺著,像睡著了一般贤徒。 火紅的嫁衣襯著肌膚如雪芹壕。 梳的紋絲不亂的頭發(fā)上汇四,一...
    開封第一講書人閱讀 51,692評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音踢涌,去河邊找鬼通孽。 笑死,一個(gè)胖子當(dāng)著我的面吹牛斯嚎,可吹牛的內(nèi)容都是我干的利虫。 我是一名探鬼主播挨厚,決...
    沈念sama閱讀 40,416評(píng)論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼堡僻,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了疫剃?” 一聲冷哼從身側(cè)響起钉疫,我...
    開封第一講書人閱讀 39,326評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎巢价,沒想到半個(gè)月后牲阁,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,782評(píng)論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡壤躲,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,957評(píng)論 3 337
  • 正文 我和宋清朗相戀三年城菊,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片碉克。...
    茶點(diǎn)故事閱讀 40,102評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡凌唬,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出漏麦,到底是詐尸還是另有隱情客税,我是刑警寧澤,帶...
    沈念sama閱讀 35,790評(píng)論 5 346
  • 正文 年R本政府宣布撕贞,位于F島的核電站更耻,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏捏膨。R本人自食惡果不足惜秧均,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,442評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望号涯。 院中可真熱鬧目胡,春花似錦、人聲如沸诚隙。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,996評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽久又。三九已至巫延,卻和暖如春效五,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背炉峰。 一陣腳步聲響...
    開封第一講書人閱讀 33,113評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工畏妖, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人疼阔。 一個(gè)月前我還...
    沈念sama閱讀 48,332評(píng)論 3 373
  • 正文 我出身青樓戒劫,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親婆廊。 傳聞我的和親對(duì)象是個(gè)殘疾皇子迅细,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,044評(píng)論 2 355

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