Linux內(nèi)核淺析-進(jìn)程地址空間

本文介紹下linux如何管理內(nèi)存。作為架構(gòu)師,我去做一個(gè)系統(tǒng)時(shí),通常從兩個(gè)方面入手:1)了解上層業(yè)務(wù)和需求勒庄。2)熟悉下層可以使用的工具和能力盐须。本質(zhì)上,做任何系統(tǒng),或者做任何事情吧,縱向上來(lái)說誉简,我們都是做上層和下層之間的樞紐,橫向上來(lái)說烹吵,我們做的是整個(gè)任務(wù)鏈上的一個(gè)節(jié)點(diǎn),也是前琼梆、后節(jié)點(diǎn)之間的傳動(dòng)齒輪艾栋。linux就是這樣蝗砾,是上層業(yè)務(wù)程序和下層體系結(jié)構(gòu)之間的樞紐,其封裝了底層體系結(jié)構(gòu)的復(fù)雜性,以更方便的操作界面供上層操作,用最近流行的一個(gè)詞語(yǔ),”認(rèn)知折疊“,那linux就是折疊了體系結(jié)構(gòu)的認(rèn)知,讓上層不必關(guān)注硬件體系結(jié)構(gòu)彭雾,而專注于自身的業(yè)務(wù)。

內(nèi)存管理的背景

上層業(yè)務(wù)需求

1、save and get:程序?qū)⑦\(yùn)行所需要的指令數(shù)據(jù)進(jìn)行暫存(不需要持久化),并在需要時(shí)能夠準(zhǔn)確索引之前暫存的任何值,并load入cpu寄存器進(jìn)行運(yùn)算。

2、安全性:要做到進(jìn)程之間的隔離,用戶態(tài)、內(nèi)核態(tài)的隔離谓苟,保證系統(tǒng)級(jí)別的安全,即使一個(gè)進(jìn)程出現(xiàn)內(nèi)存溢出、尋址越界等情況,不能影響系統(tǒng)和其他進(jìn)程的運(yùn)行曲秉。

3、高效:meta信息要少,內(nèi)存操作要快。

底層提供的能力

最底層的能力就是內(nèi)存條,能夠根據(jù)索引存儲(chǔ)數(shù)據(jù)和獲取數(shù)據(jù)塑荒,但是x86體系結(jié)構(gòu)封裝了cpu和內(nèi)存的交互過程拧篮,通過下列x86匯編完成cpu和內(nèi)存交互礁凡。

可以看到,x86提供了基于(段地址 + 段偏移)進(jìn)行存取的能力,x86內(nèi)部會(huì)將(段地址+段偏移)轉(zhuǎn)換為物理地址后進(jìn)行存儲(chǔ)状共,但地址轉(zhuǎn)換時(shí)需要依賴于頁(yè)表機(jī)制,頁(yè)表的內(nèi)容由linux寫入,整個(gè)過程后面會(huì)詳細(xì)聊到(https://zhuanlan.zhihu.com/p/82406447),此處只是了解下底層能力每庆。

可以看到伦籍,上層需要如此豐滿,底層能力如此露骨,我們通常面對(duì)的就是這種情況君珠,但這種情況下恰恰可以大有作為乐导。


1)管理的粒度:linux將內(nèi)存分頁(yè),每頁(yè)默認(rèn)大小為4k沉桌。這里有個(gè)trade off的問題,如果粒度小翠订,比如1 byte,則可以提升空間利用率巩踏,但是管理的meta信息就會(huì)很多,如果分配較大空間時(shí)牵咙,耗時(shí)就會(huì)更長(zhǎng);如果粒度大溪食,則meta信息少,分配大內(nèi)存時(shí)耗時(shí)少,但分配小塊內(nèi)存時(shí)會(huì)有浪費(fèi)。所以一般在線系統(tǒng)或者mysql庫(kù),使用默認(rèn)頁(yè)大小(此處不是只mysql的頁(yè)咖城,而是mysql使用的linux的頁(yè)),olap系統(tǒng)或者離線存儲(chǔ)系統(tǒng)一般使用大頁(yè)他匪,linux提供配置參數(shù)可以配置大頁(yè)絮供。

2)進(jìn)程地址空間:每個(gè)進(jìn)程獨(dú)有的,用字段task_struct -> mm_struct表示亲铡,其也叫線性地址,其轉(zhuǎn)換關(guān)系:線性地址 -> 邏輯地址 -> 物理地址叙谨。

解耦:因?yàn)閯偛盘岬降亩际莤86支持的方式蝠猬,還是arm等體系結(jié)果需要支持兑凿,所以linux通過進(jìn)程地址空間這個(gè)entity進(jìn)行解耦捧请,所以內(nèi)存的操作都在用戶態(tài)完成力麸,真正分配內(nèi)存時(shí)蛮粮,通過缺頁(yè)異常搞定然想。

隔離:由于進(jìn)程地址空間按進(jìn)程單位進(jìn)行隔離蛙卤,保證進(jìn)程訪問時(shí)相互隔離栅屏。同時(shí)空間內(nèi)部也分為kernel space和user space松靡,保證用戶態(tài)和內(nèi)核態(tài)的訪問的內(nèi)存相互隔離。同時(shí)采用分段機(jī)制建椰,將指令雕欺、不同類型的數(shù)據(jù)分開存儲(chǔ),以支持進(jìn)程運(yùn)行模型棉姐。

text segment:存儲(chǔ)代碼指令的區(qū)域

data segment:存儲(chǔ)已初始化的全局或靜態(tài)變量

bss segment:存儲(chǔ)未初始化的全局或靜態(tài)變量

heap:堆屠列,用于動(dòng)態(tài)開辟內(nèi)存空間,brk或malloc開辟的空間

memory mapping space:mmap系統(tǒng)調(diào)用使用的空間伞矩,通常用于文件映射到內(nèi)存或匿名映射(開辟大塊空間)笛洛,當(dāng)malloc大于128k時(shí)(此處依賴于glibc的配置),也使用該區(qū)域乃坤。在進(jìn)程創(chuàng)建時(shí)苛让,會(huì)將程序用到的平臺(tái)、動(dòng)態(tài)鏈接庫(kù)加載到該區(qū)域

stack:進(jìn)程運(yùn)行的棧

空間利用率: 由于32位只支持4G物理內(nèi)存尋址湿诊,一種方式N個(gè)進(jìn)程平分4G內(nèi)存狱杰,這是最簡(jiǎn)單的方式,但有個(gè)問題厅须,有些進(jìn)程占用內(nèi)存仿畸,但一直在sleep,相當(dāng)于很浪費(fèi)朗和。另一種方式就是把內(nèi)存空間給最需要的進(jìn)程颁湖,把sleep進(jìn)程的內(nèi)存swap到硬盤,需要的時(shí)候再swap進(jìn)內(nèi)存例隆。此時(shí)就有一種極端情況甥捺,就是一個(gè)進(jìn)程需要獨(dú)占4G內(nèi)存,linux顯然選擇第二種利用率更高的方式镀层,所以進(jìn)程地址空間能映射4G的物理內(nèi)存镰禾。

3)邏輯地址:邏輯地址 = 段地址 + 段偏移,段地址和段偏移的值由linux進(jìn)行提供唱逢。

4)頁(yè)表:保存邏輯地址到物理地址的映射吴侦,其數(shù)據(jù)由linux初始化,并將熱頁(yè)表項(xiàng)加載TLB快表進(jìn)行緩存坞古,加快轉(zhuǎn)換速度备韧。然后x86體系的硬件依賴頁(yè)表做邏輯地址 -> 物理地址的轉(zhuǎn)換。

5)伙伴系統(tǒng):管理物理內(nèi)存的分配痪枫,其在缺頁(yè)中斷中被調(diào)用织堂,僅負(fù)責(zé)更改頁(yè)表和meta(strcut page)叠艳。當(dāng)邏輯地址和物理地址映射上后,指令使用物理地址寫入內(nèi)存設(shè)備易阳。

進(jìn)程地址空間管理

struct mm_struct {

? ? struct vm_area_struct * mmap;? //指向虛擬區(qū)間(VMA)的鏈表

? ? struct rb_root mm_rb;? ? ? ? ? //指向線性區(qū)對(duì)象紅黑樹的根

? ? pgd_t * pgd;? ? ? ? ? ? ? ? ? //指向頁(yè)全局目錄

? ? unsigned long mmap_base; ? //表示mmap區(qū)域的起始位置

? ? unsigned long total_vm; ? //總共映射的頁(yè)面數(shù)附较,包括映射到內(nèi)存中和已經(jīng)換出到銀盤的

? ? unsigned long locked_vm; ? //表示不能swap到硬盤的頁(yè)數(shù)

? ? unsigned long pinned_vm; ? //表示不能換出,不能移動(dòng)的頁(yè)數(shù)

? ? unsigned long data_vm; ? //存儲(chǔ)數(shù)劇占的總頁(yè)數(shù)

? ? unsigned long exec_vm; ? //存儲(chǔ)指令占的總頁(yè)數(shù)

? ? unsigned long stack_vm; ? //棧所占的總頁(yè)數(shù)

? ? // text潦俺、data segment的開始和結(jié)束地址

? ? unsigned long start_code, end_code, start_data, end_data;

? ? // 堆的開始拒课、當(dāng)前位置。棧的起始位置事示,棧的當(dāng)前地址在esp寄存器中

? ? unsigned long start_brk, brk, start_stack;

? ? // 命令行參數(shù)列表早像、環(huán)境變量的起始、結(jié)束地址肖爵,其都位于棧的高地址

? ? unsigned long arg_start, arg_end, env_start, env_end;

}

task_struct -> mm_struct是對(duì)進(jìn)程地址空間描述的結(jié)構(gòu)體卢鹦,主要包含其統(tǒng)計(jì)信息和各個(gè)segment的起始、結(jié)束地址遏匆,幾個(gè)變量如下圖右側(cè)的標(biāo)注法挨。


進(jìn)程地址空間的地址是向上增長(zhǎng)的》福可以看到有幾個(gè)radom offset凡纳,其在段與段之間縫隙,防止固定的內(nèi)存布局被黑客黑掉帝蒿。

vm_area_struct是描述每個(gè)段具體信息結(jié)構(gòu)體荐糜,其實(shí)一個(gè)單鏈表,通過task_struct- > mm_struct -> mmap表示葛超,由于每次分配內(nèi)存時(shí)會(huì)要到vm_area_struct暴氏,需要快速尋找,所以task_struct- > mm_struct -> mm_rb是根據(jù)vm_area_struct -> vm_start字段绣张,構(gòu)建vm_area_struct的一棵紅黑樹答渔。

struct vm_area_struct {

/* The first cache line has the info for VMA tree walking. */

unsigned long vm_start; /* Our start address within vm_mm. */

unsigned long vm_end; /* The first byte after our end address within vm_mm. */

/* linked list of VM areas per task, sorted by address */

struct vm_area_struct *vm_next, *vm_prev;

struct rb_node vm_rb;

struct mm_struct *vm_mm; /* The address space we belong to. */

struct list_head anon_vma_chain; /* Serialized by mmap_sem &

? * page_table_lock */

struct anon_vma *anon_vma; /* Serialized by page_table_lock */

/* Function pointers to deal with this struct. */

const struct vm_operations_struct *vm_ops;

struct file * vm_file; /* File we map to (can be NULL). */

void * vm_private_data; /* was vm_pte (shared mem) */

} __randomize_layout;

每個(gè)字段的具體含義可以參見注釋。其中anon_vma是匿名映射侥涵,即分配大塊內(nèi)存沼撕,vm_file即是指向文件映射映射的文件。vm_ops即是這段內(nèi)存上對(duì)應(yīng)的操作芜飘。

mm_struct和vm_area_struct的初始化是在load_elf_binary的時(shí)候初始化务豺,主要做的幾個(gè)事情如下:

1)調(diào)用 setup_new_exec,設(shè)置內(nèi)存映射區(qū) mmap_base嗦明。

2)調(diào)用setup_arg_pages笼沥,設(shè)置棧的vm_area_struct和current -> mm -> start_stack。

3)調(diào)用elf_map,將elf文件中的代碼映射到對(duì)應(yīng)區(qū)域中奔浅。

4)set_brk馆纳,設(shè)置堆的vm_area_struct,current -> mm -> start_brk = current -> mm -> brk乘凸,此時(shí)棧是空的厕诡。

5)load_elf_interp將依賴的so加載到mmap區(qū)域累榜。

load_elf_binary完成后营勤,線性空間的布局就基本如上圖,當(dāng)進(jìn)程運(yùn)行時(shí)會(huì)修改椧挤#空間的大小葛作,通過malloc申請(qǐng)空間時(shí)會(huì)改變heap、mmmap空間的大小猖凛。

brk & mmap

分配內(nèi)存常使用malloc赂蠢,這是glibc提供的方法,其內(nèi)部也有block的管理辨泳。但是底層都依賴于linux提供的系統(tǒng)調(diào)用:brk和mmap虱岂。若malloc小于128k,則使用brk菠红,大于則使用mmap第岖,可通過M_MMAP_THRESHOLD修改128k這個(gè)邊界值。如下圖试溯,A = malloc(30K)蔑滓,B = malloc(40K),C = malloc(200K)遇绞,D=malloc(100K)键袱。


brk

其通過系統(tǒng)調(diào)用設(shè)置current -> mm -> brk指針,在heap空間來(lái)分配和回收內(nèi)存空間摹闽。

SYSCALL_DEFINE1(brk, unsigned long, brk)

{

unsigned long retval;

unsigned long newbrk, oldbrk;

struct mm_struct *mm = current->mm;

struct vm_area_struct *next;

? ? ? ? // 1蹄咖、如果新的brk和當(dāng)前mm->brk按頁(yè)對(duì)齊后相等,則說明不需要跨頁(yè)分配付鹿,則直接設(shè)置當(dāng)前brk即可

newbrk = PAGE_ALIGN(brk);

oldbrk = PAGE_ALIGN(mm->brk);

if (oldbrk == newbrk)

goto set_brk;

// 2澜汤、如果新的brk小于mm->brk,說明需要進(jìn)行線性空間的回收

if (brk <= mm->brk) {

if (!do_munmap(mm, newbrk, oldbrk-newbrk, &uf))

goto set_brk;

goto out;

}

// 3倘屹、找到next vma银亲,vm_start_gap可以理解返回的是next.vm_start,然后比較下一個(gè)vma和當(dāng)前vma是否

? ? ? ? // 能容納新申請(qǐng)的空間纽匙。這里有兩個(gè)注意點(diǎn):

? ? ? ? // 1)oldbrk是按頁(yè)對(duì)齊后的brk地址务蝠,此時(shí)通過fina_vma找到的是第一個(gè)滿足vma.vm_end > oldbrk的?

? ? ? ? // vma,所以是下一個(gè)vma烛缔,用next指針表示

? ? ? ? // 2)brk的入?yún)⑹且粋€(gè)addr馏段,所以只能查看當(dāng)前vma和下一個(gè)vma之間是否足夠分配轩拨,不能線性

? ? ? ? // 查找,這一點(diǎn)不同于mmap方式院喜。

next = find_vma(mm, oldbrk);

if (next && newbrk + PAGE_SIZE > vm_start_gap(next))

goto out;

? ? ? ? // 4亡蓉、對(duì)于brk,此處僅設(shè)置vm_area_struct的vm_end和其他相關(guān)指針喷舀,不會(huì)新分配vma

if (do_brk(oldbrk, newbrk-oldbrk, &uf) < 0)

goto out;

// 5砍濒、設(shè)置brk

set_brk:

mm->brk = brk;

return brk;

out:

retval = mm->brk;

return retval

mmap

通過遍歷mmap區(qū)域,找到大小合適的區(qū)域進(jìn)行文件映射或匿名映射硫麻,其入口是SYSCALL_DEFINES6爸邢,主要邏輯在do_mmap中。

unsigned long do_mmap(struct file *file, unsigned long addr,

? ? ? ? ? ? ? ? ? ? ? ? unsigned long len, unsigned long prot,

? ? ? ? ? ? ? ? ? ? ? ? unsigned long flags, vm_flags_t vm_flags,

? ? ? ? ? ? ? ? ? ? ? ? unsigned long pgoff, unsigned long *populate,

? ? ? ? ? ? ? ? ? ? ? ? struct list_head *uf) {

? ? ? ? struct mm_struct *mm = current->mm;

? ? ? ? int pkey = 0;

? ? ? ? *populate = 0;

? ? ? ? if (!len)

? ? ? ? ? ? ? ? return -EINVAL;

.......

/* pang */

? ? ? ? len = PAGE_ALIGN(len);

? ? ? ? if (!len)

? ? ? ? ? ? ? ? return -ENOMEM;

// 判斷該進(jìn)程的地址空間的虛擬區(qū)間數(shù)量是否超過了限制

? ? ? ? if (mm->map_count > sysctl_max_map_count)

? ? ? ? ? ? ? ? return -ENOMEM;

? ? // 從mmap區(qū)域獲取未被映射且length合適的vma addr

? ? ? ? addr = get_unmapped_area(file, addr, len, pgoff, flags);

.......

? ? ? ? /* file指針不為nullptr, 即從文件到虛擬空間的映射 */

? ? if (file) {

.......

? ? ? ? } else {

? ? ? ? ? ? ? ? switch (flags & MAP_TYPE) {

? ? ? ? ? ? ? ? case MAP_SHARED:

.......? ? ? ? ? ? ?

? ? ? ? ? ? ? ? case MAP_PRIVATE:

.......

? ? ? ? ? ? ? ? default:

? ? ? ? ? ? ? ? ? ? ? ? return -EINVAL;

? ? ? ? ? ? ? ? }

? ? ? ? }

? ? ? ? // 映射到vm_area_struct

? ? ? ? addr = mmap_region(file, addr, len, vm_flags, pgoff, uf);

? ? ? ? if (!IS_ERR_VALUE(addr) &&

? ? ? ? ? ? ((vm_flags & VM_LOCKED) ||

? ? ? ? ? ? (flags & (MAP_POPULATE | MAP_NONBLOCK)) == MAP_POPULATE))

? ? ? ? ? ? ? ? *populate = len;

? ? ? ? return addr;

get_unmapped_area:從mmap區(qū)域中找到未被映射拿愧,且length滿足要求的vma的起始addr杠河。

若addr != 0,則從指定addr查找浇辜。先調(diào)用fina_vma券敌,找到vma,使其滿足vma.vm_end > addr同時(shí)還需要滿足addr + len < vma.vm.start柳洋,則返回該addr待诅。

若addr == 0或步驟1找不到符合要求的addr,則從mm->free_area_cache從新開始全局搜索膳灶,如果還搜索不到咱士,就返回錯(cuò)誤。mm->free_area_cache在初始化時(shí)被設(shè)置為用戶空間的三分之一(1G的位置轧钓,1G以下是為text序厉、data、bss保留)毕箍。

mmap_region:根據(jù)addr弛房,映射vma,可能是和原有的vma合并而柑,也可能是重新創(chuàng)建vma文捶,邏輯在vma_merge中,具體可以參見http://edsionte.com/techblog/archives/3586媒咳。

線性地址與邏輯地址的映射

邏輯地址 = 段地址 + 段偏移粹排,從上圖可以看出線性地址 = 段偏移,在linux中涩澡,段地址都被初始化為0(也可參見https://zhuanlan.zhihu.com/p/73937048)顽耳。我理解原因有兩個(gè):

1)不是所有體系結(jié)構(gòu)都有段地址的概念,比如arm,linux為了支持多個(gè)體系架構(gòu)射富,所以做了兼容設(shè)計(jì)膝迎。

2)避免了一次地址轉(zhuǎn)換,使得線性地址直接對(duì)應(yīng)段偏移地址胰耗,減少了計(jì)算復(fù)雜度限次。

那為何不直接干掉段地址,linux干嘛還初始化為0柴灯?因?yàn)閤86體系要求啊卖漫,x86會(huì)通過mmu將段地址 + 段偏移 -> 物理地址,如果linux不設(shè)置段地址弛槐,x86就不work了懊亡,就沒法轉(zhuǎn)換為物理地址依啰,這個(gè)后面一篇文章會(huì)詳細(xì)講乎串。

內(nèi)核地址空間

kernel代碼運(yùn)行需要使用的內(nèi)存地址,比如創(chuàng)建task_struct描述符速警,內(nèi)核代碼運(yùn)行棧等等叹誉。

直接映射區(qū):也叫高端映射區(qū),其和物理內(nèi)存一一對(duì)應(yīng)闷旧,這并不是說內(nèi)核可以直接使用物理地址长豁,而是這段區(qū)域和物理地址的映射關(guān)系是一一對(duì)應(yīng)的。虛擬地址空間的3G + 896M直接映射物理地址的低896M忙灼。

內(nèi)核動(dòng)態(tài)映射區(qū):用戶態(tài)malloc會(huì)在堆分配匠襟,那內(nèi)核使用vmalloc函數(shù)分配的空間就在該區(qū)域。該區(qū)域和用戶區(qū)域的映射規(guī)則一樣该园。比如物理內(nèi)存896M~2G被用戶態(tài)使用酸舍,那內(nèi)核態(tài)就需要映射2G以上的物理內(nèi)存,但是內(nèi)核態(tài)的線性地址只有1G里初,此時(shí)就不能用直接映射了啃勉,該區(qū)域的映射可以映射到任何物理內(nèi)存。

永久映射區(qū):分配alloc_pages双妨,用管理物理內(nèi)存淮阐。

很多人到這里有疑問吧,為什么要有高端映射刁品?完全統(tǒng)一為動(dòng)態(tài)映射泣特,用戶態(tài)和內(nèi)核態(tài)保持一致不就ok??jī)?nèi)核需要保證足夠的物理內(nèi)存來(lái)運(yùn)行挑随,如果這段區(qū)域不連續(xù)的話状您,不方便統(tǒng)計(jì),每次用戶態(tài)分配內(nèi)存時(shí)是不是都要檢查?那干脆加一個(gè)直接映射區(qū)竞阐,同時(shí)讓用戶態(tài)無(wú)法映射到該物理區(qū)域就ok了缴饭。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市骆莹,隨后出現(xiàn)的幾起案子颗搂,更是在濱河造成了極大的恐慌,老刑警劉巖幕垦,帶你破解...
    沈念sama閱讀 206,311評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件丢氢,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡先改,警方通過查閱死者的電腦和手機(jī)疚察,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)仇奶,“玉大人貌嫡,你說我怎么就攤上這事「盟荩” “怎么了岛抄?”我有些...
    開封第一講書人閱讀 152,671評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)狈茉。 經(jīng)常有香客問我夫椭,道長(zhǎng),這世上最難降的妖魔是什么氯庆? 我笑而不...
    開封第一講書人閱讀 55,252評(píng)論 1 279
  • 正文 為了忘掉前任蹭秋,我火速辦了婚禮,結(jié)果婚禮上堤撵,老公的妹妹穿的比我還像新娘仁讨。我一直安慰自己,他們只是感情好粒督,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評(píng)論 5 371
  • 文/花漫 我一把揭開白布陪竿。 她就那樣靜靜地躺著,像睡著了一般屠橄。 火紅的嫁衣襯著肌膚如雪族跛。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,031評(píng)論 1 285
  • 那天锐墙,我揣著相機(jī)與錄音礁哄,去河邊找鬼。 笑死溪北,一個(gè)胖子當(dāng)著我的面吹牛桐绒,可吹牛的內(nèi)容都是我干的夺脾。 我是一名探鬼主播,決...
    沈念sama閱讀 38,340評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼茉继,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼咧叭!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起烁竭,我...
    開封第一講書人閱讀 36,973評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤菲茬,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后派撕,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體婉弹,經(jīng)...
    沈念sama閱讀 43,466評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評(píng)論 2 323
  • 正文 我和宋清朗相戀三年终吼,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了镀赌。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,039評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡际跪,死狀恐怖商佛,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情垫卤,我是刑警寧澤威彰,帶...
    沈念sama閱讀 33,701評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站穴肘,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏舔痕。R本人自食惡果不足惜评抚,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望伯复。 院中可真熱鬧慨代,春花似錦、人聲如沸啸如。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)叮雳。三九已至想暗,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間帘不,已是汗流浹背说莫。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留寞焙,地道東北人储狭。 一個(gè)月前我還...
    沈念sama閱讀 45,497評(píng)論 2 354
  • 正文 我出身青樓互婿,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親辽狈。 傳聞我的和親對(duì)象是個(gè)殘疾皇子慈参,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評(píng)論 2 345

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