內(nèi)存管理二

Autoreleasepool

Autoreleasepool的結(jié)構(gòu)

我們的main函數(shù)中定義一個(gè)自動(dòng)釋放池

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        
    }
    
    return 0;
}

然后通過clang查看源碼實(shí)現(xiàn)

/* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool; 

    }

可以看到我們的@autoreleasepool轉(zhuǎn)換成了__AtAutoreleasePool进泼,__AtAutoreleasePool的實(shí)現(xiàn)如下:

struct __AtAutoreleasePool {
  __AtAutoreleasePool() {atautoreleasepoolobj = objc_autoreleasePoolPush();}
  ~__AtAutoreleasePool() {objc_autoreleasePoolPop(atautoreleasepoolobj);}
  void * atautoreleasepoolobj;
};

__AtAutoreleasePool有兩個(gè)方法廓啊,一個(gè)是push()腻贰,一個(gè)是pop()绑榴。
通過符號(hào)斷點(diǎn)的方式可以確定objc_autoreleasePoolPush在objc的源碼中笼痛,然后我們找到對(duì)應(yīng)的源碼:

void *
objc_autoreleasePoolPush(void)
{
    return AutoreleasePoolPage::push();
}

調(diào)用了AutoreleasePoolPage的push()函數(shù)。AutoreleasePoolPage是一頁鸟废,相當(dāng)于自動(dòng)釋放池中的好多對(duì)象組成了這樣的一頁拾碌,然后每一頁又連起來形成了一個(gè)雙向的鏈表結(jié)構(gòu)。定位到AutoreleasePoolPage的定義:

/***********************************************************************
   Autorelease pool implementation
    // 先進(jìn)后出
   A thread's autorelease pool is a stack of pointers. 
   Each pointer is either an object to release, or POOL_BOUNDARY which is 
     an autorelease pool boundary.
   A pool token is a pointer to the POOL_BOUNDARY for that pool. When 
     the pool is popped, every object hotter than the sentinel is released.
   The stack is divided into a doubly-linked list of pages. Pages are added 
     and deleted as necessary. 
   Thread-local storage points to the hot page, where newly autoreleased 
     objects are stored. 
**********************************************************************/
class AutoreleasePoolPage : private AutoreleasePoolPageData

通過注釋我們可以發(fā)現(xiàn):

  • AutoreleasePoolPage是個(gè)棧的結(jié)構(gòu)第喳,也就是先進(jìn)后出糜俗;
  • AutoreleasePoolPage中的節(jié)點(diǎn)有兩種:要釋放的對(duì)象以及pool boundary(也就是邊界值)。
  • page會(huì)組成一個(gè)雙向鏈接的結(jié)構(gòu)曲饱;
  • tls 線程存儲(chǔ)悠抹;

然后看下AutoreleasePoolPageData的實(shí)現(xiàn):

struct AutoreleasePoolPageData
{
    magic_t const magic; // 16
    __unsafe_unretained id *next; //8
    pthread_t const thread; // 8
    AutoreleasePoolPage * const parent; //8
    AutoreleasePoolPage *child; //8
    uint32_t const depth; // 4
    uint32_t hiwat; // 4

    AutoreleasePoolPageData(__unsafe_unretained id* _next, pthread_t _thread, AutoreleasePoolPage* _parent, uint32_t _depth, uint32_t _hiwat)
        : magic(), next(_next), thread(_thread),
          parent(_parent), child(nil),
          depth(_depth), hiwat(_hiwat)
    {
    }
};

next是定位偏移;thread為關(guān)聯(lián)的線程扩淀;parent為父節(jié)點(diǎn)楔敌;child為子節(jié)點(diǎn);
下面我們看下AutoreleasePoolPage的初始化方法:

AutoreleasePoolPage(AutoreleasePoolPage *newParent) :
        AutoreleasePoolPageData(begin(),
                                objc_thread_self(),
                                newParent,
                                newParent ? 1+newParent->depth : 0,
                                newParent ? newParent->hiwat : 0)
    { 
        if (parent) {
            parent->check();
            ASSERT(!parent->child);
            parent->unprotect();
            parent->child = this;
            parent->protect();
        }
        protect();
    }

可見驻谆,初始化方法中調(diào)用了AutoreleasePoolPageData的初始化方法卵凑,傳入了begin()。begin()就是AutoreleasePoolPage的地址除去上面的那個(gè)magic胜臊、next勺卢、thread、parrent象对、child等屬性后的位置黑忱。也就是開始存儲(chǔ)pointer的地方了。
自動(dòng)釋放池的結(jié)構(gòu)如下织盼,每個(gè)AutoreleasePoolPage作為一個(gè)雙向鏈表的節(jié)點(diǎn)杨何。AutoreleasePoolPage的頭部位置存儲(chǔ)著一些屬性:magic、next等沥邻。

自動(dòng)釋放池的結(jié)構(gòu)

下面我們向自動(dòng)釋放池中添加一些對(duì)象危虱,然后打印一下

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        
        for (int i = 0; i<5; i++) {
            NSObject *obj = [[NSObject alloc] autorelease];
            NSLog(@"%@", obj);
        }
        _objc_autoreleasePoolPrint();
    }
    
    return 0;
}

打印結(jié)果如下:

objc[18996]: ##############
objc[18996]: AUTORELEASE POOLS for thread 0x1000d1dc0
objc[18996]: 6 releases pending.
objc[18996]: [0x100804000]  ................  PAGE  (hot) (cold)
objc[18996]: [0x100804038]  ################  POOL 0x100804038
objc[18996]: [0x100804040]       0x1006b8ee0  NSObject
objc[18996]: [0x100804048]       0x101100200  NSObject
objc[18996]: [0x100804050]       0x101300020  NSObject
objc[18996]: [0x100804058]       0x10063d6c0  NSObject
objc[18996]: [0x100804060]       0x1006b5e60  NSObject
objc[18996]: ##############

地址0x100804000到0x100804038存儲(chǔ)的是AutoreleasePoolPage的一些頭部屬性信息。然后從0x100804038開始存儲(chǔ)了6個(gè)對(duì)象唐全,但是我們自己是創(chuàng)建了5個(gè)對(duì)象埃跷。還有一個(gè)就是我們哨兵對(duì)象蕊玷,也就是邊界對(duì)對(duì)象。這個(gè)邊界對(duì)象是自動(dòng)釋放池的邊界弥雹,當(dāng)嵌套使用自動(dòng)釋放池的時(shí)候垃帅,每個(gè)自動(dòng)釋放池都會(huì)有對(duì)象的邊界。
當(dāng)我們自動(dòng)釋放池的對(duì)象超過505的時(shí)候剪勿,就會(huì)進(jìn)行分頁贸诚,創(chuàng)建新的AutoreleasePoolPage。也就是說一個(gè)AutoreleasePoolPage只能裝505個(gè)對(duì)象厕吉,注意因?yàn)榈谝粋€(gè)需要有個(gè)邊界對(duì)象酱固,所以只能有504個(gè)對(duì)象。

Autoreleasepool的壓棧

首先找到objc_autoreleasePoolPush函數(shù)头朱,調(diào)用了push函數(shù)

void *
objc_autoreleasePoolPush(void)
{
    return AutoreleasePoolPage::push();
}

push函數(shù)中調(diào)用autoreleaseFast函數(shù)

static inline void *push() 
    {
        id *dest;
        if (slowpath(DebugPoolAllocation)) {
            // Each autorelease pool starts on a new pool page.
            dest = autoreleaseNewPage(POOL_BOUNDARY);
        } else {
            dest = autoreleaseFast(POOL_BOUNDARY);
        }
        ASSERT(dest == EMPTY_POOL_PLACEHOLDER || *dest == POOL_BOUNDARY);
        return dest;
    }

autoreleaseFast函數(shù)中运悲,如果存在page并且page沒有滿,就會(huì)調(diào)用page->add(obj)函數(shù)向page中添加對(duì)象项钮;如果page已滿了班眯,調(diào)用autoreleaseFullPage;如果還沒有創(chuàng)建page烁巫,那么使用autoreleaseNoPage進(jìn)行創(chuàng)建署隘。

static inline id *autoreleaseFast(id obj)
{
    AutoreleasePoolPage *page = hotPage();
    if (page && !page->full()) {
        return page->add(obj);
    } else if (page) {
        return autoreleaseFullPage(obj, page);
    } else {
        return autoreleaseNoPage(obj);
    }
}
  • 首先我們來看下創(chuàng)建page的函數(shù)autoreleaseNoPage
// Install the first page.
AutoreleasePoolPage *page = new AutoreleasePoolPage(nil);
setHotPage(page);

// Push a boundary on behalf of the previously-placeholder'd pool.
if (pushExtraBoundary) {
    page->add(POOL_BOUNDARY);
}

// Push the requested object or pool.
return page->add(obj);

主要就是創(chuàng)建了Page,然后設(shè)置為聚焦page程拭,如果是第一個(gè)page就先插入邊界定踱,然后再插入對(duì)象。

  • 然后看下page->add(obj)函數(shù)向存在的page中添加對(duì)象恃鞋。
id *add(id obj)
{
    ASSERT(!full());
    unprotect();
    id *ret = next;  // faster than `return next-1` because of aliasing
    *next++ = obj;
    protect();
    return ret;
}

很簡(jiǎn)單崖媚,就是移動(dòng)next的位置,指向obj恤浪。

  • 最后我們看下page滿的情況:autoreleaseFullPage函數(shù)實(shí)現(xiàn)
do {
    if (page->child) page = page->child;
    else page = new AutoreleasePoolPage(page);
} while (page->full());

setHotPage(page);
return page->add(obj);

一個(gè)doWhile循環(huán)畅哑,查找child,也就是雙鏈表中的那個(gè)節(jié)點(diǎn)水由。知道找到?jīng)]有裝滿的page荠呐,如果找到最后找不到,就創(chuàng)建一個(gè)新的砂客。然后設(shè)置為hotPage泥张,最后添加對(duì)象進(jìn)去。
上面就是我們的壓棧過程鞠值。

Autoreleasepool的出棧

首先是objc_autoreleasePoolPop函數(shù)媚创,該函數(shù)的參數(shù)是調(diào)用pagePush的時(shí)候返回的對(duì)象。也就是該page的上下文標(biāo)識(shí)彤恶。

void
objc_autoreleasePoolPop(void *ctxt)
{
    AutoreleasePoolPage::pop(ctxt);
}

然后調(diào)用pop函數(shù)钞钙,pop函數(shù)的主要內(nèi)容為:

AutoreleasePoolPage *page;
id *stop;
page = pageForPointer(token);
stop = (id *)token;
return popPage<false>(token, page, stop);

根據(jù)上下文找到對(duì)應(yīng)的page鳄橘,然后調(diào)用popPage函數(shù)。popPage函數(shù)的試下如下:

popPage(void *token, AutoreleasePoolPage *page, id *stop)
{
    if (allowDebug && PrintPoolHiwat) printHiwat();

    page->releaseUntil(stop);

    // memory: delete empty children
    if (allowDebug && DebugPoolAllocation  &&  page->empty()) {
        // special case: delete everything during page-per-pool debugging
        AutoreleasePoolPage *parent = page->parent;
        page->kill();
        setHotPage(parent);
    } else if (allowDebug && DebugMissingPools  &&  page->empty()  &&  !page->parent) {
        // special case: delete everything for pop(top)
        // when debugging missing autorelease pools
        page->kill();
        setHotPage(nil);
    } else if (page->child) {
        // hysteresis: keep one empty child if page is more than half full
        if (page->lessThanHalfFull()) {
            page->child->kill();
        }
        else if (page->child->child) {
            page->child->child->kill();
        }
    }
}

調(diào)用page->releaseUntil(stop);釋放對(duì)象芒炼。后面就是對(duì)page的kill處理以及setHotPage處理瘫怜。下面看下releaseUntil函數(shù):

void releaseUntil(id *stop) 
{
    // Not recursive: we don't want to blow out the stack 
    // if a thread accumulates a stupendous amount of garbage
    
    while (this->next != stop) {
        // Restart from hotPage() every time, in case -release 
        // autoreleased more objects
        AutoreleasePoolPage *page = hotPage();

        // fixme I think this `while` can be `if`, but I can't prove it
        while (page->empty()) {
            page = page->parent;
            setHotPage(page);
        }

        page->unprotect();
        id obj = *--page->next;
        memset((void*)page->next, SCRIBBLE, sizeof(*page->next));
        page->protect();

        if (obj != POOL_BOUNDARY) {
            objc_release(obj);
        }
    }

    setHotPage(this);
}

一個(gè)while循,移動(dòng)next指本刽,依次給對(duì)象發(fā)送release消息鲸湃,如果page為空,就開始處理父節(jié)點(diǎn)盅安,設(shè)置父節(jié)點(diǎn)為hotPage唤锉,直到遍歷到邊界。

Autoreleasepool的嵌套

下面的代碼中别瞭,我們開啟了一個(gè)子線程,子線程會(huì)自動(dòng)創(chuàng)建一個(gè)自動(dòng)釋放池株憾。

@autoreleasepool {
    // insert code here...
    // 1 + 504 + 505 + 505
    NSObject *objc = [[NSObject alloc] autorelease];
    NSLog(@"objc = %@",objc);
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
            NSObject *obj = [[NSObject alloc] autorelease];
            NSLog(@"\n\n obj = %@",obj);
            _objc_autoreleasePoolPrint();
    });
    _objc_autoreleasePoolPrint();
}

然后我們得到下面的打印結(jié)果:

2020-03-22 22:03:55.610864+0800 KCObjcTest[20399:607121] objc = <NSObject: 0x100686c80>
objc[20399]: ##############
objc[20399]: AUTORELEASE POOLS for thread 0x1000d2dc0
objc[20399]: 2 releases pending.
objc[20399]: [0x100812000]  ................  PAGE  (hot) (cold)
objc[20399]: [0x100812038]  ################  POOL 0x100812038
objc[20399]: [0x100812040]       0x100686c80  NSObject
objc[20399]: ##############
2020-03-22 22:03:55.612082+0800 KCObjcTest[20399:607493] 

 obj = <NSObject: 0x1010026e0>
objc[20399]: ##############
objc[20399]: AUTORELEASE POOLS for thread 0x70000e5c0000
objc[20399]: 2 releases pending.
objc[20399]: [0x102802000]  ................  PAGE  (hot) (cold)
objc[20399]: [0x102802038]  ################  POOL 0x102802038
objc[20399]: [0x102802040]       0x1010026e0  NSObject
objc[20399]: ##############

因?yàn)樽詣?dòng)釋放池是和線程相關(guān)的蝙寨,所以主線程和子線程都會(huì)創(chuàng)建對(duì)應(yīng)線程的AutoReleasePool,然后分別存儲(chǔ)一個(gè)邊界對(duì)象和一個(gè)正常的對(duì)象嗤瞎。
下面我們?cè)谧泳€程中再次手動(dòng)創(chuàng)建一個(gè)autoreleasepool墙歪,那么子線程就會(huì)有兩個(gè)autoreleasepool了。

@autoreleasepool {
    // insert code here...
    // 1 + 504 + 505 + 505
    NSObject *objc = [[NSObject alloc] autorelease];
    NSLog(@"objc = %@",objc);
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        @autoreleasepool {
            NSObject *obj = [[NSObject alloc] autorelease];
            NSLog(@"\n\n obj = %@",obj);
            _objc_autoreleasePoolPrint();
       }
    });
    _objc_autoreleasePoolPrint();
}

打印結(jié)果如下:

2020-03-22 22:07:02.159829+0800 KCObjcTest[20445:609384] objc = <NSObject: 0x100712a10>
objc[20445]: ##############
objc[20445]: AUTORELEASE POOLS for thread 0x1000d2dc0
objc[20445]: 2 releases pending.
2020-03-22 22:07:02.161109+0800 KCObjcTest[20445:609762] 

 obj = <NSObject: 0x100644f60>
objc[20445]: [0x102803000]  ................  PAGE  (hot) (cold)
objc[20445]: [0x102803038]  ################  POOL 0x102803038
objc[20445]: [0x102803040]       0x100712a10  NSObject
objc[20445]: ##############
objc[20445]: ##############
objc[20445]: AUTORELEASE POOLS for thread 0x700007752000
objc[20445]: 3 releases pending.
objc[20445]: [0x101801000]  ................  PAGE  (hot) (cold)
objc[20445]: [0x101801038]  ################  POOL 0x101801038
objc[20445]: [0x101801040]  ################  POOL 0x101801040
objc[20445]: [0x101801048]       0x100644f60  NSObject
objc[20445]: ##############
Program ended with exit code: 0

可見子線程中的page中變成了3個(gè)對(duì)象贝奇,有兩個(gè)邊界虹菲。分別標(biāo)識(shí)這兩個(gè)autoreleasepool的作用域。但是一個(gè)線程值創(chuàng)建了一個(gè)page掉瞳。

RunLoop

RunLoop的底層實(shí)現(xiàn)是個(gè)doWhile循環(huán)毕源。

void CFRunLoopRun(void) {    /* DOES CALLOUT */
    int32_t result;
    do {
        result = CFRunLoopRunSpecific(CFRunLoopGetCurrent(), kCFRunLoopDefaultMode, 1.0e10, false);
        CHECK_FOR_FORK();
    } while (kCFRunLoopRunStopped != result && kCFRunLoopRunFinished != result);
}

依賴于RunLoop的六大事件:


RunLoop六大事件

我們通過CFRunLoopGetMain來獲取runLoop。

CFRunLoopRef CFRunLoopGetMain(void) {
    CHECK_FOR_FORK();
    static CFRunLoopRef __main = NULL; // no retain needed
    if (!__main) __main = _CFRunLoopGet0(pthread_main_thread_np()); // no CAS needed
    return __main;
}

_CFRunLoopGet0的主要實(shí)現(xiàn):創(chuàng)建一個(gè)dict陕习,然后將線程和runloop對(duì)應(yīng)著放到dict中霎褐。所以說RunLoop和線程是一一對(duì)應(yīng)的。

CFMutableDictionaryRef dict = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, NULL, &kCFTypeDictionaryValueCallBacks);
// 進(jìn)行綁定 dict[@"pthread_main_thread_np"] = mainLoop
CFDictionarySetValue(dict, pthreadPointer(pthread_main_thread_np()), mainLoop);

CFRunLoopRef newLoop = __CFRunLoopCreate(t);
CFDictionarySetValue(__CFRunLoops, pthreadPointer(t), newLoop);

RunLoop是個(gè)結(jié)構(gòu)體该镣,包含的以下內(nèi)容:

pthread_t _pthread;
CFMutableSetRef _commonModes;
CFMutableSetRef _commonModeItems;
CFRunLoopModeRef _currentMode;
CFMutableSetRef _modes;

_pthread為綁定的線程冻璃,還有包含的modes、items损合。他們的關(guān)系圖如下:


runLoop結(jié)構(gòu)

一個(gè)runLoop對(duì)應(yīng)一個(gè)線程省艳,對(duì)應(yīng)N個(gè)Mode。一個(gè)Mode對(duì)應(yīng)N個(gè)source嫁审、timer跋炕、observer。

RunLoop調(diào)用timer等事件

下面我們看下timer事件是怎么依賴于RunLoop執(zhí)行的呢土居?
首先我們創(chuàng)建一個(gè)timer枣购,然后在timer的執(zhí)行block的地方打上斷點(diǎn)嬉探,查看堆棧調(diào)用情況。

timer的調(diào)用棧

在timer的block執(zhí)行之前的函數(shù)調(diào)用順序?yàn)椋?br> __CFRunLoopRun棉圈,__CFRunLoopDoTimers(timer事件可能會(huì)有很多涩堤,所以是個(gè)集合體), __CFRunLoopDoTimer分瘾, __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__
如果是其他的事件的話胎围,流程相似,只不過是換成對(duì)應(yīng)的__CFRunLoopDoSources0德召、__CFRunLoopDoSource1白魂、__CFRunLoopDoObservers__CFRunLoopDoBlocks上岗。

RunLoop的函數(shù)實(shí)現(xiàn)
  • 通知觀察者即將進(jìn)入RunLoop福荸;
  • 使用dispatch_source_t構(gòu)建一個(gè)定時(shí)器來控制runLoop的超時(shí)退出。CFRunLoopRun() 默認(rèn)的超時(shí)時(shí)間很大肴掷,所以直接設(shè)置為不超時(shí)敬锐,此時(shí)就不需要定時(shí)器了;
  • 然后進(jìn)入一個(gè)doWhile循環(huán);
  • 這里有個(gè)內(nèi)循環(huán),用于接收等待端口的消息呆瞻。進(jìn)入此循環(huán)后台夺,線程進(jìn)入休眠,直到收到新消息才跳出該循環(huán)痴脾,繼續(xù)執(zhí)行run loop颤介;
    調(diào)用 mach_msg 等待接受 mach_port 的消息。線程將進(jìn)入休眠, 直到被下面某一個(gè)事件喚醒赞赖。
    1滚朵、一個(gè)基于 port 的Source 的事件;
    2薯定、一個(gè) Timer 到時(shí)間了始绍;
    3、RunLoop 自身的超時(shí)時(shí)間到了话侄;
    4亏推、被其他什么調(diào)用者手動(dòng)喚醒。

RunLoop循環(huán)退出的條件:
1年堆、進(jìn)入loop時(shí)標(biāo)記了stopAfterHandle參數(shù)吞杭,也就是處理完事件就返回,那么處理完成事件后直接退出变丧;
2芽狗、timer到期了;
3痒蓬、被外部調(diào)用者強(qiáng)制停止了童擎,通過CFRunLoopStop函數(shù)設(shè)置的滴劲;
4、設(shè)置停止顾复,通過_CFRunLoopStopMode設(shè)置停止班挖;
5、source/timer/observer一個(gè)都沒有了芯砸。

RunLoop的流程圖
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末萧芙,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子假丧,更是在濱河造成了極大的恐慌双揪,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,248評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件包帚,死亡現(xiàn)場(chǎng)離奇詭異渔期,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)渴邦,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門擎场,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人几莽,你說我怎么就攤上這事≌玻” “怎么了章蚣?”我有些...
    開封第一講書人閱讀 153,443評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長姨夹。 經(jīng)常有香客問我纤垂,道長,這世上最難降的妖魔是什么磷账? 我笑而不...
    開封第一講書人閱讀 55,475評(píng)論 1 279
  • 正文 為了忘掉前任峭沦,我火速辦了婚禮,結(jié)果婚禮上逃糟,老公的妹妹穿的比我還像新娘吼鱼。我一直安慰自己,他們只是感情好绰咽,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,458評(píng)論 5 374
  • 文/花漫 我一把揭開白布菇肃。 她就那樣靜靜地躺著,像睡著了一般取募。 火紅的嫁衣襯著肌膚如雪琐谤。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,185評(píng)論 1 284
  • 那天玩敏,我揣著相機(jī)與錄音斗忌,去河邊找鬼质礼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛织阳,可吹牛的內(nèi)容都是我干的眶蕉。 我是一名探鬼主播,決...
    沈念sama閱讀 38,451評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼陈哑,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼妻坝!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起惊窖,我...
    開封第一講書人閱讀 37,112評(píng)論 0 261
  • 序言:老撾萬榮一對(duì)情侶失蹤刽宪,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后界酒,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體圣拄,經(jīng)...
    沈念sama閱讀 43,609評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,083評(píng)論 2 325
  • 正文 我和宋清朗相戀三年毁欣,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了庇谆。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,163評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡凭疮,死狀恐怖饭耳,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情执解,我是刑警寧澤寞肖,帶...
    沈念sama閱讀 33,803評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站衰腌,受9級(jí)特大地震影響新蟆,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜右蕊,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,357評(píng)論 3 307
  • 文/蒙蒙 一琼稻、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧饶囚,春花似錦帕翻、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至闹丐,卻和暖如春横殴,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評(píng)論 1 261
  • 我被黑心中介騙來泰國打工衫仑, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留梨与,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,636評(píng)論 2 355
  • 正文 我出身青樓文狱,卻偏偏與公主長得像粥鞋,于是被迫代替她去往敵國和親岛蚤。 傳聞我的和親對(duì)象是個(gè)殘疾皇子贱勃,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,925評(píng)論 2 344

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