深入理解計(jì)算機(jī)系統(tǒng)


title: 深入理解計(jì)算機(jī)系統(tǒng)
date: 2019-12-10 19:29:57
tags: [計(jì)算機(jī)基礎(chǔ), 操作系統(tǒng)]
typora-copy-images-to: ./深入理解計(jì)算機(jī)系統(tǒng)
typora-root-url: ../_posts


本筆記內(nèi)容來(lái)自,深入理解計(jì)算機(jī)系統(tǒng),現(xiàn)代操作系統(tǒng),操作系統(tǒng)精髓與設(shè)計(jì)原理

程序的機(jī)器級(jí)表示

編譯的過(guò)程

如圖所示

首先,c預(yù)處理器把源文件中的#include指定的文件都插入源文件,并擴(kuò)展替換#define聲明的宏.然后編譯器把源文件轉(zhuǎn)成匯編文件(里邊都是匯編指令),然后由匯編器轉(zhuǎn)成可重定位目標(biāo)程序(也就是機(jī)器碼,但還缺少一些東西,如全局地址),最后由連接器把目標(biāo)文件和庫(kù)函數(shù)合并,并產(chǎn)生全局地址.生產(chǎn)最終可執(zhí)行程序.

匯編代碼常用寄存器

pc 指向要執(zhí)行的指令的地址

sp 程序的棧指針,通過(guò)移動(dòng)rsp來(lái)實(shí)現(xiàn)棧的pop和push

其他寄存器,不同的CPU架構(gòu)是不同的,這是x86-64的指令,可以看到同一個(gè)地址,如果先代表不同位數(shù)的數(shù)據(jù),可以用不同名的寄存器,如 rax,eax,ax,al 都是一個(gè)寄存器地址,只是用不同長(zhǎng)度來(lái)裝某個(gè)數(shù)據(jù).這是因?yàn)镃PU的尋址位數(shù)在增加.而又要兼容原來(lái)的程序.

image-20191210210938841

尋址方式

尋址方式就是指令執(zhí)行時(shí)選擇從哪個(gè)地址或數(shù)據(jù)進(jìn)行操作.這個(gè)地址由操作數(shù)提供

  • 立即數(shù)尋址 立即數(shù)就是要操作的值.這里不需要尋址.直接得到了操作要操作的值

movl $0x1234,%eax //把1234的值賦給 eax寄存器 %eax= 0x1234

  • 寄存器尋址 從一個(gè)寄存器中讀取數(shù)據(jù)或者寫(xiě)入一個(gè)數(shù)據(jù)

mov %bp ,%sp //把%bp 的內(nèi)容寫(xiě)出到 %sp中 %sp=%bp

  • 絕對(duì)尋址 就是直接把一個(gè)數(shù)值作為內(nèi)存地址進(jìn)行使用

mov %bp ,1213 //把%bp的值移動(dòng)到地址1213處

  • 間接尋址 操作數(shù)是一個(gè)寄存器,而這個(gè)寄存器的值才是真正要操作的地址,因此要先通過(guò)操作數(shù)找到改寄存器,在讀出寄存器的值作為地址

mov %bp, (%sp) //把寄存器sp的值,作為一個(gè)地址,然后把寄存器%bp的值存入這個(gè)地址中

  • 基地址+偏移量尋址 給出一個(gè)基地址,并加上一個(gè)位移,得到的新地址用來(lái)操作

mov %bp, 3(%sp) //把sp的值作為基地址,在加上3個(gè)地址位移得到新地址,把bp的值寫(xiě)到這個(gè)新地址

下圖中,imm表示是數(shù)字,ra,rb表示寄存器, R[ra]表示ra寄存器的值,M[addr] 表示addr元素的地址.

image-20191210214831260

條件碼

有一個(gè)寄存器,專門(mén)保存指令執(zhí)行過(guò)程中的狀態(tài).每條指令執(zhí)行時(shí)會(huì)在更新這個(gè)寄存器的某個(gè)位,來(lái)進(jìn)行跳轉(zhuǎn).

image-20191211193450004

之后的跳轉(zhuǎn)指令,就直接可以使用這個(gè)標(biāo)記位.如 jump指令中的 jne 表示不等時(shí)跳轉(zhuǎn)(jump not equal)

過(guò)程

軟件執(zhí)行時(shí),要在內(nèi)存中分配空間,內(nèi)存是連續(xù)的存儲(chǔ)數(shù)據(jù).他并不區(qū)分代碼和程序,是人為把代碼和程序放到不同地方產(chǎn)生不同的做用.

image-20191211200327550

每個(gè)進(jìn)程的大概空間分布都是類似的.在不同的函數(shù)中進(jìn)行跳轉(zhuǎn)時(shí).其實(shí)就是pc寄存器指向了不同的地址.比如由p進(jìn)函數(shù)換到q函數(shù).就需要把p函數(shù)的數(shù)據(jù)先暫時(shí)保存起來(lái).然后為q分配空間.然后執(zhí)行q.在q執(zhí)行完成后.要把q保存的數(shù)據(jù)返回并釋放.再把p函數(shù)的數(shù)據(jù)加載回來(lái).繼續(xù)執(zhí)行p.

image-20191211200718155

存儲(chǔ)器層次

存儲(chǔ)設(shè)備

靜態(tài)RAM(SRAM) 通電后可以保持穩(wěn)定的數(shù)據(jù)狀態(tài)

動(dòng)態(tài)RAM(DRAM) 通電后數(shù)據(jù)狀態(tài)只能保存100毫秒內(nèi),因此需要反復(fù)讀出,重寫(xiě)回去來(lái)刷新數(shù)據(jù).

DRAM比SRAM慢10多倍,但是容量更大.

這兩種存儲(chǔ)器需要通電才能有數(shù)據(jù).因此只能做內(nèi)存.叫做易失性存儲(chǔ).

磁盤(pán)和固態(tài)硬盤(pán)是非易失性存儲(chǔ).但是讀取速度慢.硬盤(pán)還需要尋道尋址.讀取數(shù)據(jù),更慢.而固態(tài)硬盤(pán)在多次讀寫(xiě)后會(huì)損壞,失去存儲(chǔ)的能力.

寄存器是讀寫(xiě)最快的存儲(chǔ)結(jié)構(gòu),但是容量有限.因此和alu計(jì)算單元封裝到一起.構(gòu)成CPU

image-20191211202637990

傳輸過(guò)程

數(shù)據(jù)通過(guò)總線在CPU和內(nèi)存之間傳輸.CPU把要讀取的數(shù)據(jù)的內(nèi)存地址放在總線上.傳輸給內(nèi)存.內(nèi)存得到地址后,找到對(duì)應(yīng)的數(shù)據(jù).放在總線上傳輸給CPU.

image-20191211203052699

所有的硬件通過(guò)一層控制器來(lái)連接到總線,使CPU可以忽略硬件的差異.內(nèi)存中有專門(mén)為硬件保留的內(nèi)存地址,找個(gè)地址專門(mén)給硬件保留.這叫內(nèi)存映射io.每個(gè)控制器會(huì)有幾個(gè)寄存器與CPU進(jìn)行通信.

硬件有塊設(shè)備和字符設(shè)備.字符設(shè)備就是通過(guò)流來(lái)交流信息.而塊設(shè)備是以塊為單位可以單獨(dú)的讀寫(xiě).每個(gè)塊有自己的地址.流設(shè)備就只能從頭讀到尾了. 硬件設(shè)備通話還有緩沖區(qū).等數(shù)據(jù)達(dá)到一定大小在進(jìn)行傳送.

DMA 直接內(nèi)存訪問(wèn).就是數(shù)據(jù)不經(jīng)過(guò)CPU.直接由內(nèi)存和硬盤(pán)或者內(nèi)存和硬件進(jìn)行數(shù)據(jù)通信的方式.這種過(guò)程總.又CPU發(fā)出命令告訴哪些數(shù)據(jù)從內(nèi)存中讀寫(xiě)到那里.然后內(nèi)存通過(guò)總線執(zhí)行,數(shù)據(jù)傳輸完成夠通知CPU.CPU只參與傳輸?shù)拈_(kāi)頭和結(jié)尾.

image-20191211204333468

硬盤(pán)中讀寫(xiě)數(shù)據(jù),一般是以頁(yè)作為最小單位.頁(yè)大小通常為512字節(jié)-4KB, 通常固態(tài)需要在寫(xiě)之前擦除舊數(shù)據(jù).才能后寫(xiě)入新內(nèi)容.而擦除是以塊為單位,1塊=32-128頁(yè).寫(xiě)的時(shí)候則是以頁(yè)為單位寫(xiě).有事塊中有碎片.為了寫(xiě)入數(shù)據(jù),可能要把整個(gè)塊讀取.在從新寫(xiě)入.(為了寫(xiě)4kb的數(shù)據(jù),讀出512kb的塊在寫(xiě)回.稱為寫(xiě)入放大效應(yīng))

局部性原理

通常代碼和數(shù)據(jù)總是連貫的進(jìn)行處理和執(zhí)行的.這就是局部性原理.就是在內(nèi)從中.指令通常在一個(gè)局部控件執(zhí)行.這可以提高執(zhí)行性能.

image-20191211205414559

存儲(chǔ)器金字塔

image-20191211205443747

不同的存儲(chǔ)器是一種取舍的關(guān)系.在結(jié)合局部性原理.就產(chǎn)生了優(yōu)化的控件.簡(jiǎn)單來(lái)說(shuō)就是把一個(gè)小局部?jī)?nèi)的代碼和數(shù)據(jù)放到告訴緩存中執(zhí)行.其他放在外邊低速存儲(chǔ)中.隨著指令的不斷執(zhí)行.不斷有新的數(shù)據(jù)和代碼被從低速存儲(chǔ)移動(dòng)到高速緩存.而執(zhí)行完的數(shù)據(jù)和代碼在寫(xiě)回到低速存儲(chǔ).這就使得好像是整個(gè)程序都在高速緩存中執(zhí)行.提高了性能,節(jié)省了成本.

執(zhí)行流程

程序執(zhí)行的過(guò)程其實(shí)就是pc指向一個(gè)指令的地址,把這個(gè)指令讀取進(jìn)來(lái),然后把操作數(shù)也讀取進(jìn)來(lái),把結(jié)果傳給alu計(jì)算單元處理.再把結(jié)果寫(xiě)出去,pc指向下一個(gè)指令.在重復(fù)上述的過(guò)程.

而引入緩存之后,pc先從緩存總讀取指令(通過(guò)地址來(lái)知道讀取什么指令),緩存中保存一個(gè)動(dòng)態(tài)的映射表,通過(guò)CPU的地址得到正確的數(shù)據(jù).如果讀到了.就按照之前的步驟執(zhí)行,把結(jié)果在寫(xiě)到緩存中(通常數(shù)據(jù)和指令的緩存是分開(kāi)的),如果緩存中沒(méi)有要執(zhí)行的指令,就會(huì)產(chǎn)生一個(gè)缺頁(yè)異常,交給CPU中的MMU單元去處理,這個(gè)過(guò)程比較耗時(shí),CPU可以切換到別的進(jìn)程處理別的工作.MMU會(huì)從低速存儲(chǔ)中把這個(gè)地址對(duì)應(yīng)的指令或者他前后的一片數(shù)據(jù)都讀取到內(nèi)存中(因?yàn)榭偸且粭l指令一條指令的讀,可能就產(chǎn)生很多的缺頁(yè)異常),同時(shí)更新緩存的映射表.然后在發(fā)起一個(gè)中斷指令通知CPU,數(shù)據(jù)已經(jīng)有緩存了.CPU在切會(huì)改進(jìn)程繼續(xù)從緩存中執(zhí)行.

這里可以看到,cpu總是和緩存直接打交道.CPU和內(nèi)存或硬盤(pán)并不直接溝通.總是把數(shù)據(jù)讀取到緩存中在進(jìn)行處理.(就像董事長(zhǎng)和干活的小弟之間總是有很多層領(lǐng)導(dǎo).小弟是見(jiàn)不到領(lǐng)導(dǎo)的..)

如果緩存滿了.就把比較不常用的頁(yè)寫(xiě)回到內(nèi)存或者硬盤(pán)中,這個(gè)頁(yè)交犧牲頁(yè)面.

image-20191211211208087

這里有個(gè)要點(diǎn),是緩存的內(nèi)容總是經(jīng)常變動(dòng)的.他的索引經(jīng)常變動(dòng).他返回的數(shù)據(jù)也經(jīng)常變動(dòng).這里使用了一個(gè)類似hashlist的解構(gòu),這樣加快的尋找的方式.當(dāng)然組成方式也有好幾種.這里大概

image-20191211212109772

地址被解析.先查租索引,在查t表示找到哪一行,最后查b塊便宜..這種三級(jí)查找會(huì)比較快.因?yàn)橐恍芯彺娴膬?nèi)容總是遠(yuǎn)多于一個(gè)指令或者一個(gè)數(shù)據(jù)的大小的.

鏈接

所有的程序在最終執(zhí)行時(shí)都會(huì)轉(zhuǎn)變成二進(jìn)制的機(jī)器碼來(lái)執(zhí)行,二匯編代碼其實(shí)是和機(jī)器碼等價(jià)的類似 1 和一的關(guān)系,匯編碼就是對(duì)人友好寫(xiě).并且機(jī)器碼和匯編碼這一層,是不存在數(shù)據(jù)結(jié)構(gòu)和對(duì)象這類東西的.他們只有棧和寄存器和內(nèi)存中的地址,因此機(jī)器碼操作數(shù)據(jù)需要通過(guò)地址(棧的移動(dòng)或是特定寄存器或是特定內(nèi)存)來(lái)進(jìn)行增刪改查,因此機(jī)器碼中,一定會(huì)對(duì)有內(nèi)存地址的這一部分.而程序從不是孤單的運(yùn)行的.他總會(huì)調(diào)用別人的庫(kù).調(diào)用系統(tǒng)的函數(shù).而這些函數(shù)并不是我們自己寫(xiě)的.隱藏肯定存在一個(gè)把我們的程序和庫(kù)函數(shù)系統(tǒng)函數(shù)整合起來(lái)的過(guò)程.

目標(biāo)文件

image-20191212185804307

這個(gè)很好理解.自己的代碼經(jīng)過(guò)編譯器和匯編器形成可重定位文件.在經(jīng)過(guò)連接器就變成可執(zhí)行目標(biāo)文件.共享目標(biāo)文件就是系統(tǒng)的調(diào)用函數(shù)或者共享庫(kù).

?
image-20191212204056051

這是linux的elf可重定位目標(biāo)文件常用格式.下面做些描述

  • ELF頭 這里描述的文件的一些基本信息,如文件大小,文件類型,機(jī)器類型,等

  • text 這里是已編譯的程序的機(jī)器代碼(二進(jìn)制數(shù)據(jù))

  • rodata 只讀數(shù)據(jù)

  • data 已經(jīng)初始化的全局變量和靜態(tài)變量(static 變量),局部變量保存在運(yùn)行時(shí)的棧上,

  • bss 未初始化的或者初始化為0的全局變量和靜態(tài)變量.這時(shí)bss不占用空間,在運(yùn)行時(shí)bss在占用空間

  • symtab 符號(hào)表,是程序中函數(shù)和全局變量的一種符號(hào)表示的集合,

  • rel.text 是text節(jié)中位置的表,用來(lái)存放代碼重定位條目,就是記錄代碼中引用和符號(hào)映射關(guān)系的表

  • rel.data 是data中位置的記錄,用來(lái)存放全局變量的重定位條目,就是記錄全局變量和靜態(tài)變量引用和符號(hào)映射關(guān)系的表

  • line 原始c程序的行號(hào)和text指令直接的映射表

  • strtab 字符串表,保存所有程序中的字符串,包含函數(shù)名,和全局變量名

鏈接過(guò)程

image

在機(jī)器指令和匯編層面.是不存在函數(shù)和全局變量的.因此在編譯的某一部會(huì)把這些函數(shù)和全局變量的引用轉(zhuǎn)化為具體的地址.這是在鏈接過(guò)程實(shí)現(xiàn).

鏈接分為兩個(gè)步驟.符號(hào)解析和重定位.

符號(hào)和符號(hào)表

符號(hào)對(duì)應(yīng)于一個(gè)函數(shù),一個(gè)全局變量或者一個(gè)靜態(tài)變量(局部變量在運(yùn)行時(shí)由棧上產(chǎn)生,因此不需要進(jìn)行處理)

符號(hào)解析就是遍歷匯編器產(chǎn)生的可重定位文件.把里邊的所有對(duì)函數(shù)和全局變量,生成對(duì)應(yīng)的符號(hào),這里還會(huì)區(qū)分是本文件內(nèi)的符號(hào)(本地符號(hào))還是引用的外部定義的符號(hào)(全局符號(hào)).

int f(){
    static int b =5;
    return "hello";
}
這段代碼.在匯編器中就把 f作為一個(gè)函數(shù)符號(hào).b作為靜態(tài)變量保存在符號(hào)表中,符號(hào)表會(huì)記錄他們的類型和他們的名稱和位置.

符號(hào)表就是程序中所有符號(hào)的集合,符號(hào)結(jié)構(gòu)如下

image-20191212205953428

包括符號(hào)名name,符號(hào)地址 value,符號(hào)大小 size, 符號(hào)類型(變量還是函數(shù))type,本地變量還是全局變量 binding

通過(guò)符號(hào),就把程序中的 方法名和全局變量進(jìn)行了抽象話.最后符號(hào)都會(huì)轉(zhuǎn)化為一個(gè)地址.

image-20191212210241121

上邊表示 main函數(shù)的符號(hào),是全局符號(hào)(global),是一個(gè)方法(func),大小是24字節(jié),

符號(hào)解析

符號(hào)解析就是把程序中的引用(引用就是對(duì)方法的調(diào)用,對(duì)變量的調(diào)用)同符號(hào)表中的某個(gè)符號(hào)關(guān)聯(lián)起來(lái),生成一個(gè)重定位條目,這就建立了一個(gè) 引用--符號(hào) 的映射表.這個(gè)表叫做重定位表.代碼的重定位表在elf結(jié)構(gòu)的rel.text里.全局變量和靜態(tài)變量的重定位表在elf結(jié)構(gòu)的rel.data里.對(duì)于外部定義的全局變量,生成重定位條目比較麻煩.有一下規(guī)則

image-20191212211554394

靜態(tài)庫(kù)連接

程序在開(kāi)發(fā)中,不可避免的要引入第三方庫(kù)和系統(tǒng)庫(kù)的函數(shù).而這些函數(shù)在生成可執(zhí)行文件時(shí),需要一同打進(jìn)來(lái).但是這些函數(shù)也經(jīng)常需要開(kāi)發(fā)迭代.因此引入了靜態(tài)庫(kù)連接的方式.把所有的庫(kù)函數(shù)的可重定位目標(biāo)文件打包成單獨(dú)的一個(gè)文件.在鏈接過(guò)程中,連接器把程序需要的可重定位目標(biāo)文件加載到我們自己的文件中,把沒(méi)有引用到的都拋棄掉.

image-20191212212008054

最終就是使 未解析的符號(hào)集合U變?yōu)榭?然后E就是我們的程序生成的可執(zhí)行文件.

重定位

因?yàn)榉?hào)解析階段已經(jīng)建立了符號(hào)條目和程序引用的映射關(guān)系.這里通過(guò)一系列措施,使引用指向真正的指令執(zhí)行的地址.這里由兩部組成

  • 合并可執(zhí)行文件的所有同類型的節(jié).就是把幾個(gè)可重定位文件文件的data節(jié)合并到一起,把text節(jié)合并到一起等等.此時(shí)就形成了一個(gè)可重定位文件.它的所有節(jié)都是統(tǒng)一的.然后把符號(hào)表中的符號(hào)賦值真正運(yùn)行時(shí)的地址.
  • 通過(guò)遍歷rel.data和rel.text 重定位條目表,把對(duì)符號(hào)的引用替換成真正的運(yùn)行時(shí)地址.大概操作是通過(guò)引用找到符號(hào),此時(shí)符號(hào)是真正地址,通過(guò)計(jì)算得到引用的真正地址.

這樣.所有的引用都轉(zhuǎn)成了真正的地址.此時(shí)就成了可執(zhí)行文件了.]

可執(zhí)行文件

image-20191212213241216

此時(shí)text 和data和rodata這些節(jié)已經(jīng)保存了要運(yùn)行時(shí)的地址了.在執(zhí)行時(shí),代碼和數(shù)據(jù)會(huì)分別加載到內(nèi)存中連續(xù)的內(nèi)存段.因此段頭部表保存這個(gè)映射關(guān)系. 這里涉及到了內(nèi)存映射和虛擬內(nèi)存的知識(shí).下邊是進(jìn)程在內(nèi)存中的映像,每個(gè)進(jìn)程都是這樣

image-20191212214232583

程序執(zhí)行時(shí),系統(tǒng)把可執(zhí)行文件的代碼和數(shù)據(jù)復(fù)制到代碼段和讀寫(xiě)段中,然后調(diào)用main函數(shù)開(kāi)始執(zhí)行.堆和棧會(huì)在運(yùn)行時(shí)變化.

動(dòng)態(tài)連接

動(dòng)態(tài)連接就是在運(yùn)行時(shí)或者加載時(shí),可以加載到任意的內(nèi)存地址,并和一個(gè)在內(nèi)存中的程序連接起來(lái).也就是在運(yùn)行時(shí)進(jìn)行進(jìn)行連接.系統(tǒng)中的庫(kù)函數(shù)就通過(guò)動(dòng)態(tài)連接,分享給不同的進(jìn)程,這樣節(jié)省空間.

動(dòng)態(tài)連接不會(huì)在鏈接過(guò)程合并到程序中,而是保持在一個(gè).interp的節(jié)里,在運(yùn)行時(shí),把動(dòng)態(tài)庫(kù)的指令和數(shù)據(jù)重定向到某個(gè)內(nèi)存段,然后修改上文的符號(hào)表,給符號(hào)以正確的地址,在通過(guò)重定位表使引用找到正確的地址.

加載連接場(chǎng)景

image-20191217212424738

跳轉(zhuǎn)控制

image-20191214113723294

異常發(fā)生過(guò)程,在應(yīng)用程序執(zhí)行到某個(gè)地方時(shí),觸發(fā)異常,產(chǎn)生一個(gè)特定的異常號(hào).由這個(gè)異常號(hào)去查系統(tǒng)內(nèi)部的遺產(chǎn)表,找到對(duì)應(yīng)異常處理程序,然后保存應(yīng)用程序的數(shù)據(jù)狀態(tài),跳轉(zhuǎn)到異常處理程序執(zhí)行.異常處理程序運(yùn)行在內(nèi)核狀態(tài)下.可以操控所以資源.異常處理完成后.返回原來(lái)的程序繼續(xù)執(zhí)行.或者終止程序執(zhí)行.

異常表是操縱系統(tǒng)中對(duì)所有異常處理程序的索引表.通過(guò)異常號(hào)可以找到對(duì)應(yīng)的異常處理程序.異常執(zhí)行時(shí).從用戶態(tài)轉(zhuǎn)向內(nèi)核態(tài),源程序的數(shù)據(jù)壓入到內(nèi)核態(tài)的棧上.

異常的類別

image-20191214113955381
  • 中斷來(lái)自于io信號(hào).是異步發(fā)送,異步中斷是通知CPU有外界信息需要交互了.要進(jìn)行處理.CPU執(zhí)行完中斷程序后.繼續(xù)執(zhí)行原來(lái)的程序
  • 陷阱就是系統(tǒng)調(diào)用,就是程序調(diào)用系統(tǒng)的服務(wù),比如創(chuàng)建進(jìn)程,然后把運(yùn)行權(quán)限交給系統(tǒng)執(zhí)行,系統(tǒng)執(zhí)行晚餐后返回
  • 故障是代碼執(zhí)行錯(cuò)誤,CPU會(huì)把故障交個(gè)故障處理程序執(zhí)行,如果能解決,就返回源程序的指令.如果不能返回就終止.
  • 終止就會(huì)結(jié)束程序.由不可恢復(fù)的錯(cuò)誤導(dǎo)致.

進(jìn)程

進(jìn)程就是運(yùn)行中的代碼和數(shù)據(jù)和程序運(yùn)行所需要的狀態(tài)信息的集合.這個(gè)狀態(tài)包括棧,寄存器的內(nèi)容.程序計(jì)數(shù)器,環(huán)境變量和打開(kāi)的文件描述符.

image-20191214115102541

操作系統(tǒng)的機(jī)制使我們以為我們的程序在獨(dú)占CPU進(jìn)行執(zhí)行,而其實(shí)他們是并發(fā)執(zhí)行的.在大的時(shí)間尺度上并行執(zhí)行,而在時(shí)間片上則是輪流執(zhí)行.

為了使系統(tǒng)更安全.處理器要對(duì)不同的程序作出限制,這就產(chǎn)生了內(nèi)核模式和用戶模式.

內(nèi)核模式的進(jìn)程可以執(zhí)行指令集中的任何指令,并訪問(wèn)內(nèi)存中的任何位置

用戶模式的進(jìn)程只能訪問(wèn)一部分指令,不允許訪問(wèn)內(nèi)核的代碼和數(shù)據(jù).用戶模式的進(jìn)程只能通過(guò)跳轉(zhuǎn)控制來(lái)間接的訪問(wèn)內(nèi)核代碼和數(shù)據(jù).

內(nèi)核進(jìn)程和用戶進(jìn)程,由某個(gè)控制進(jìn)存器的一個(gè)模式位來(lái)指定的.

進(jìn)程在概念上完整的擁有自己的CPU.而每個(gè)CPU只能真正一次運(yùn)行一個(gè)進(jìn)程.通過(guò)在不同進(jìn)程進(jìn)行切換,達(dá)到了多進(jìn)程執(zhí)行的假象.

進(jìn)程的創(chuàng)建

進(jìn)程總是由一個(gè)已知的正在運(yùn)行的進(jìn)程,通過(guò)一個(gè)系統(tǒng)調(diào)用,通知操作系統(tǒng)來(lái)創(chuàng)建.

linux中通過(guò)fork創(chuàng)建進(jìn)程,子進(jìn)程和父進(jìn)程共享內(nèi)存影映像,環(huán)境字符串和打開(kāi)的文件. windows使用creattProcess創(chuàng)建進(jìn)程,可以指定新進(jìn)程的各種屬性

子進(jìn)程和父進(jìn)程具有不同的地址空間,其中發(fā)送對(duì)數(shù)據(jù)的修改.都導(dǎo)致對(duì)其他進(jìn)程不可見(jiàn).意思是,只讀的內(nèi)存區(qū)是共享的,可寫(xiě)的內(nèi)存區(qū)通過(guò)寫(xiě)時(shí)復(fù)制,映射到新的地址,因此寫(xiě)的內(nèi)存是進(jìn)程獨(dú)自享有.

進(jìn)程的狀態(tài)

image-20191214180844044

進(jìn)程的狀態(tài)切換由進(jìn)程調(diào)度程序控制,進(jìn)程調(diào)度程序是操作系統(tǒng)的一部分,對(duì)進(jìn)程不可見(jiàn).

操作系統(tǒng)維護(hù)一個(gè)進(jìn)程表,每個(gè)進(jìn)程占表格的一項(xiàng),保存進(jìn)程的所有相關(guān)信息.如下

image-20191214181252945

詳細(xì)的進(jìn)程狀態(tài)切換,進(jìn)程被換出內(nèi)存.就變成了掛起態(tài).換回內(nèi)存是就緒態(tài).

image-20191217204928478

上下文切換

上下文就是一個(gè)進(jìn)程在運(yùn)行時(shí)需要的全部資料.包括棧,寄存器的內(nèi)容.程序計(jì)數(shù)器,環(huán)境變量和打開(kāi)的文件描述符.每個(gè)進(jìn)程的上下文都是不一樣的.

進(jìn)程切換時(shí),要由內(nèi)核中的調(diào)度器的程序執(zhí)行.1.他把原來(lái)進(jìn)程的上下文進(jìn)行保存,2.在恢復(fù)或加載另外進(jìn)程的上下文,3.將控制傳遞給這個(gè)新回復(fù)的進(jìn)程. 因此上下文切換總會(huì)先進(jìn)入內(nèi)核態(tài)的調(diào)度器.

image-20191214120211399

進(jìn)程切換的大概步驟

image-20191217205740228
image-20191217205751080

信號(hào)

信號(hào)就是一個(gè)小消息,通知進(jìn)程發(fā)生了某種類型的事件.信號(hào)提供了一種機(jī)制,內(nèi)核用來(lái)通知用戶進(jìn)程發(fā)生了異常.

image-20191214120931563

信號(hào)通常由內(nèi)核發(fā)送,因?yàn)樗拍芨虏煌舷挛倪M(jìn)程的狀態(tài).

接受信號(hào)的進(jìn)程通過(guò)信號(hào)處理程序來(lái)捕獲這個(gè)信號(hào).(這就應(yīng)該是我們代碼的try..catch捕獲異常)

image-20191214121126451

中斷發(fā)生的大概邏輯如下,簡(jiǎn)單說(shuō)就說(shuō)保存原進(jìn)程的信息,加載新進(jìn)程的信息,然后執(zhí)行.中斷向量包含中斷服務(wù)程序的入口地址

image-20191214181627452

線程

進(jìn)程和線程的區(qū)別

線程可以共享地址空間和數(shù)據(jù).而進(jìn)程獨(dú)享地址空間和數(shù)據(jù).

線程比進(jìn)程更輕量.所以他的切換和創(chuàng)建銷毀更快速.

多個(gè)線程可以共享公共內(nèi)存.因此更容易進(jìn)行通信

線程必須在進(jìn)程中運(yùn)行,但是進(jìn)程和線程是不同的東西,線程擁有自己的程序計(jì)數(shù)器,寄存器,和一個(gè)堆棧.

進(jìn)程是資源的聚合體.而線程則是CPU上被調(diào)度的實(shí)體.線程可以訪問(wèn)進(jìn)程地址空間中的每一個(gè)內(nèi)存地址,甚至可以訪問(wèn)其他線程的堆棧,因此線程之間是沒(méi)有保護(hù)的.

image-20191214182627084

線程的抽象

這是所有線程都具有的抽象的功能

image-20191214183313525

線程的實(shí)現(xiàn)方式

有兩種.在用戶態(tài)實(shí)現(xiàn)和在內(nèi)核態(tài)實(shí)現(xiàn)

image-20191214184032401

用戶態(tài)線程

把線程放在用戶空間中,內(nèi)核對(duì)線程一無(wú)所知.優(yōu)點(diǎn)是可以再不支持線程的操作系統(tǒng)中在用戶空間實(shí)現(xiàn)線程機(jī)制

此時(shí)線程的調(diào)度都有用戶程序控制,因此每個(gè)進(jìn)程都要有專門(mén)的線程表,用來(lái)跟蹤控制線程.由運(yùn)行時(shí)系統(tǒng)管理.

線程的切換只在用戶進(jìn)程中完成,十分迅速.還可以對(duì)每個(gè)進(jìn)程指定不同的線程切換調(diào)度算法.

缺點(diǎn)是在執(zhí)行系統(tǒng)調(diào)用如io或中斷時(shí),一個(gè)線程的操作可能導(dǎo)致整個(gè)進(jìn)程被阻塞了.影響改進(jìn)程的全部線程.

還有就是針對(duì)進(jìn)程的調(diào)度算法對(duì)線程不可用(因?yàn)檫M(jìn)程的調(diào)度在內(nèi)核態(tài),而內(nèi)核不知道有線程),線程間的調(diào)度需要進(jìn)程來(lái)自己控制.防止被某線程獨(dú)占.

內(nèi)核態(tài)線程

此時(shí)不需要運(yùn)行時(shí)系統(tǒng),進(jìn)程也不管理線程表.線程表由內(nèi)核來(lái)管理.內(nèi)核通過(guò)管理進(jìn)程表和線程表來(lái)管理調(diào)度進(jìn)程和線程.

優(yōu)點(diǎn)是當(dāng)一個(gè)線程進(jìn)行io操作被阻塞,內(nèi)核可以選擇改進(jìn)程的其他線程繼續(xù)執(zhí)行.

缺點(diǎn)是開(kāi)銷大.線程的切換也需要陷入內(nèi)核中在跳回用戶進(jìn)程.

混合實(shí)現(xiàn)

還有一種優(yōu)化是混合實(shí)現(xiàn),內(nèi)核只識(shí)別調(diào)度內(nèi)核級(jí)線程,內(nèi)核線程可能綁定多個(gè)用戶態(tài)線程.

image-20191214184945522

線程切換模型

進(jìn)程間通信

競(jìng)爭(zhēng)條件(race condition 翻譯真爛,應(yīng)該叫競(jìng)爭(zhēng)的情況) 當(dāng)兩個(gè)或多個(gè)進(jìn)程讀取相同的數(shù)據(jù),如果因?yàn)椴煌M(jìn)程執(zhí)行的實(shí)際不同,導(dǎo)致結(jié)果不同,稱為競(jìng)爭(zhēng)條件.也就是相同多進(jìn)程的代碼執(zhí)行多次,可能結(jié)果并不相同.

臨界區(qū)(critical region ) 對(duì)共享內(nèi)存的進(jìn)行訪問(wèn)的代碼稱為臨界區(qū).使多個(gè)進(jìn)程不能同時(shí)處于臨界區(qū),就可以避免競(jìng)爭(zhēng)條件的發(fā)生.

通過(guò)臨界區(qū)的互斥,保證執(zhí)行結(jié)果唯一,下邊介紹幾種方式

image-20191214190002197

常用的并發(fā)機(jī)制

image-20191217210743030

忙等待的互斥

image-20191214190609061

通過(guò)不斷的循環(huán),測(cè)試一個(gè)變量的值知道他出現(xiàn)為止,稱為忙等待,這種方法很浪費(fèi)CPU,且需要另外進(jìn)程改變這個(gè)變量才行.這要求必須是abab 這樣交替執(zhí)行.

另一種方式 TSL 測(cè)試并加鎖,這是一種硬件設(shè)施 如 TSL RX, LOCK

image-20191214191109455

這就保證當(dāng)lock 為0時(shí),任何進(jìn)程都可以執(zhí)行TSL指令,但是只會(huì)有1個(gè)進(jìn)程a執(zhí)行成功,然后lock變?yōu)榉橇?這個(gè)進(jìn)程a就可以訪問(wèn)共享內(nèi)存.其他進(jìn)程只能等待TSL變?yōu)?,進(jìn)程a執(zhí)行完成后用move指令把lock 變?yōu)? ,其他進(jìn)程就再次搶奪執(zhí)行TSL指令.

忙等待的缺點(diǎn)是等待的進(jìn)程一直等在這里空轉(zhuǎn).浪費(fèi)資源. 還好產(chǎn)生優(yōu)先級(jí)反轉(zhuǎn)問(wèn)題.

image-20191214191740280

生產(chǎn)者消費(fèi)者問(wèn)題就是用了忙等待的互斥方法

image-20191214192118134
image-20191214192327641

信號(hào)量

image-20191214192957339

down和睡眠是原子性的.up和喚醒也是原子性的. 睡眠后和喚醒后.信號(hào)量都被釋放可供其他進(jìn)程執(zhí)行.

down可能會(huì)導(dǎo)致睡眠. up可能會(huì)導(dǎo)致喚醒.

可以看下面代碼.對(duì)緩沖區(qū)數(shù)據(jù)的操作前后肯定是要對(duì)mutex信號(hào)量進(jìn)行排他的.而生產(chǎn)者還需要執(zhí)行down(&empty)是為了確保有空槽.完成后up(&full)通知消費(fèi)者又有了一個(gè)產(chǎn)品.消費(fèi)者執(zhí)行的過(guò)程同理,確保有滿槽,然后對(duì) mutex執(zhí)行前后排他.消費(fèi)完成后通知生產(chǎn)者又有了空槽.這里是用empty和full兩個(gè)信號(hào)量來(lái)控制緩沖區(qū)是否有數(shù)目

image-20191214193453401

互斥量

互斥量就是簡(jiǎn)化的信號(hào)量.他只有兩個(gè)狀態(tài).加鎖和解鎖.0表示解鎖.非零表示加鎖,只有一個(gè)線程可以加鎖.其他進(jìn)程在調(diào)用加鎖就會(huì)被阻塞,等到加鎖的進(jìn)程調(diào)用解鎖后.從阻塞的所有進(jìn)程里取一個(gè)進(jìn)行恢復(fù),在執(zhí)行

image-20191214195607614

互斥量比忙等待的優(yōu)點(diǎn)就是.阻塞的進(jìn)程會(huì)放棄CPU的只用權(quán),轉(zhuǎn)而執(zhí)行其他進(jìn)程.當(dāng)阻塞的進(jìn)程恢復(fù)時(shí)在執(zhí)行.這提高了CPU的執(zhí)行效率.

管程

信號(hào)量的缺點(diǎn)就是有時(shí)需要多個(gè)信號(hào)量來(lái)保證臨界區(qū)的唯一性.如上文的生產(chǎn)者消費(fèi)者. 這里的信號(hào)量的順序不可以改變.否則會(huì)死鎖.這種方式不友好.因此提出了管程.

管程在任意時(shí)候只能有一個(gè)活躍進(jìn)程.管程的互斥性由編譯器實(shí)現(xiàn).原理其實(shí)還是信號(hào)量.

管程可以有多個(gè)條件變量.進(jìn)程可以阻塞在某個(gè)條件變量處.然后讓出管程的所有權(quán).讓其他進(jìn)程進(jìn)入管程執(zhí)行.也就是管程總是只有一個(gè)活動(dòng)的進(jìn)程.但可以有多個(gè)阻塞在條件變量上的進(jìn)程.當(dāng)執(zhí)行的進(jìn)程退出時(shí),會(huì)喚醒其中一個(gè)阻塞的進(jìn)程,該阻塞的進(jìn)程從被阻塞出繼續(xù)執(zhí)行.

通過(guò)wait阻塞在某個(gè)條件.通過(guò)signl被喚醒. wait操作必須在signl之前.且signl最好作為管程過(guò)程的最好一個(gè)語(yǔ)句.

在java語(yǔ)言中,wait和notify等價(jià)于上文的wait和signl. 而synchronize則提供了管程的概念.下邊看下java語(yǔ)言的管程實(shí)現(xiàn)的生產(chǎn)者消費(fèi)者

管程的缺點(diǎn)是依賴于語(yǔ)言來(lái)實(shí)現(xiàn).有的語(yǔ)言沒(méi)有.

image-20191214201024704

消息傳遞

消息傳遞通過(guò)send(destination,&msg) 和recevie(source,*msg)來(lái)實(shí)現(xiàn),接收方會(huì)一直等待消息到達(dá).這種方式通常用于網(wǎng)絡(luò)通信.

消息中采用一個(gè)信箱.對(duì)一定數(shù)據(jù)進(jìn)行緩存.生產(chǎn)者接受到一個(gè)空消息,就發(fā)送一個(gè)有用消息.注意下邊代碼里雙方都使用receive 和send.也就是雙方雙向等待消息.

image-20191214201934124

屏障

屏障用于一組進(jìn)程,是他們用相同的節(jié)奏進(jìn)行執(zhí)行.先執(zhí)行到屏障處的進(jìn)程被攔截.直到所有進(jìn)程都到達(dá)屏障,然后同步繼續(xù)執(zhí)行.

image-20191214202433289

管道

管道是一個(gè)環(huán)形緩沖區(qū),先進(jìn)先出的單向隊(duì)列,由一個(gè)進(jìn)程寫(xiě),另一個(gè)進(jìn)程讀.一次只有一個(gè)進(jìn)程可以進(jìn)入管道.寫(xiě)滿了會(huì)阻塞,讀空了也會(huì)阻塞.

進(jìn)程調(diào)度

  • 調(diào)度原因

    不同的進(jìn)程都是執(zhí)行io請(qǐng)求和計(jì)算交替的.而進(jìn)程執(zhí)行io時(shí)為了不浪費(fèi)CPU.需要調(diào)度別的進(jìn)程來(lái)執(zhí)行

  • 何時(shí)調(diào)度

    進(jìn)程創(chuàng)建時(shí),進(jìn)程退出時(shí),進(jìn)程阻塞在io操作時(shí),io操作完成發(fā)出io中斷時(shí).

  • 調(diào)度分類

    批處理,就是批量的處理一批任務(wù)

    交互式,就是與用戶進(jìn)行交互操作.

    實(shí)時(shí),必須在特定的時(shí)間完成任務(wù).

  • 調(diào)度的目標(biāo)

    吞吐量是系統(tǒng)每小時(shí)完成的作業(yè)書(shū).周轉(zhuǎn)時(shí)間是一個(gè)作業(yè)從提交到完成所需要的平均時(shí)間.

image-20191214203002437

調(diào)度算法

批處理系統(tǒng)的調(diào)度算法

先來(lái)先服務(wù)

按照作業(yè)的請(qǐng)求順序來(lái)執(zhí)行.用一個(gè)隊(duì)列來(lái)實(shí)現(xiàn)就可以.先來(lái)的先執(zhí)行.后來(lái)的排在后邊.

優(yōu)點(diǎn)是設(shè)計(jì)簡(jiǎn)單.缺點(diǎn)是沒(méi)有針對(duì)作業(yè)的特性做優(yōu)化.比如先進(jìn)去的是復(fù)雜作業(yè).后進(jìn)入的是簡(jiǎn)單作業(yè),簡(jiǎn)單作業(yè)就要等待很長(zhǎng)時(shí)間才能開(kāi)始執(zhí)行.

最短作業(yè)優(yōu)先

把所有作業(yè)排序,把讓執(zhí)行時(shí)間段的作業(yè)先完成.這需要保證所有作業(yè)同時(shí)到達(dá).然后進(jìn)行排序.如果短作業(yè)比長(zhǎng)作業(yè)晚很久到達(dá).那么久沒(méi)法做最短優(yōu)先

最短剩余時(shí)間優(yōu)先

看那個(gè)作業(yè)剩余執(zhí)行時(shí)間最短,通過(guò)調(diào)度讓他先執(zhí)行,這需要估計(jì)程序的運(yùn)行時(shí)間.

交互式系統(tǒng)的調(diào)度算法

輪轉(zhuǎn)調(diào)度

每個(gè)進(jìn)程分配一個(gè)時(shí)間片.時(shí)間片到了.就切換到下一個(gè)進(jìn)程執(zhí)行.

進(jìn)程切換需要時(shí)間.因此時(shí)間片的長(zhǎng)度選擇也需要權(quán)衡.

image-20191214204253201

優(yōu)先級(jí)調(diào)度

給每個(gè)進(jìn)程設(shè)置一個(gè)優(yōu)先級(jí).高優(yōu)先級(jí)的進(jìn)程先運(yùn)行.也可以是高優(yōu)先級(jí)的進(jìn)程擁有更多的時(shí)間片.還可以按優(yōu)先級(jí)給進(jìn)程分組.不同組之間用優(yōu)先級(jí)調(diào)度.同組之間用輪轉(zhuǎn)調(diào)度.缺點(diǎn)是低優(yōu)先級(jí)進(jìn)程可能會(huì)長(zhǎng)時(shí)間得不到執(zhí)行

image-20191214204508488

最短進(jìn)程優(yōu)先

推測(cè)出執(zhí)行時(shí)間最短的進(jìn)程,讓他先執(zhí)行,但這個(gè)比較困難,因?yàn)槭墙换ナ较到y(tǒng),很多不可知的因素.

保證調(diào)度

保證每個(gè)進(jìn)程有公平的資源來(lái)執(zhí)行.需要計(jì)算進(jìn)程運(yùn)行了多久,來(lái)分配后邊給他運(yùn)行的時(shí)間

彩票調(diào)度

隨機(jī)抽取進(jìn)程來(lái)執(zhí)行.還可以根據(jù)優(yōu)先級(jí),給高優(yōu)先級(jí)的進(jìn)程更高抽取幾率來(lái)執(zhí)行.

實(shí)時(shí)系統(tǒng)的調(diào)度

按照要求的截止時(shí)間來(lái)完成調(diào)度.

線程調(diào)度

線程調(diào)度要看線程是在內(nèi)核態(tài)還是在用戶態(tài),如果在用戶態(tài).由進(jìn)程控制線程的調(diào)度.內(nèi)核只控制進(jìn)程的調(diào)出.這樣的方式開(kāi)銷小.如果在內(nèi)核態(tài).內(nèi)核控制內(nèi)核線程的調(diào)度,在調(diào)度時(shí)需要進(jìn)行用戶進(jìn)程的切換.這種開(kāi)銷比較大.

image-20191214205602429

哲學(xué)家就餐問(wèn)題

這里的解法就是哲學(xué)家要保證左右兩人都沒(méi)有就餐,才可以鎖定左右兩個(gè)餐刀進(jìn)餐,如果左右兩邊有一個(gè)人進(jìn)餐,就得放棄他的所有餐刀.

image-20191214210300958
image-20191214210315014
image-20191214210325009

讀者寫(xiě)者問(wèn)題

image-20191214210353394

內(nèi)存管理

內(nèi)存管理總結(jié)

image-20191217211727918

內(nèi)存要解決的問(wèn)題,如下圖.當(dāng)兩個(gè)程序都加載到內(nèi)存中(c)時(shí),如果使用物理地址,一個(gè)進(jìn)程的跳轉(zhuǎn)指令可能跳轉(zhuǎn)到另一個(gè)程序的地址上.這是災(zāi)難.

image-20191216195045541

為了解決這個(gè)問(wèn)題.要對(duì)每個(gè)程序解決重定位和包含的問(wèn)題.因此產(chǎn)生地址空間.

地址空間就是一個(gè)進(jìn)程可以在內(nèi)存尋址的一套地址空間.每個(gè)進(jìn)程有自己獨(dú)立的地址空間.并且獨(dú)立于其他進(jìn)程.

內(nèi)存交換技術(shù)

把一個(gè)完成的進(jìn)程加載到內(nèi)存中,讓他運(yùn)行一段時(shí)間,然后把它換出到磁盤(pán).把其他進(jìn)程加載到內(nèi)存中.

缺點(diǎn)是需要把運(yùn)行的進(jìn)程完整換入換出.耗費(fèi)時(shí)間.還會(huì)產(chǎn)生內(nèi)存空洞,又需要對(duì)空閑內(nèi)存進(jìn)行壓縮.還需要內(nèi)存比運(yùn)行的程序大才行.

image-20191216195632006

空閑內(nèi)存管理

當(dāng)內(nèi)存中進(jìn)程進(jìn)行不斷的換入換出.由于進(jìn)程大小不一.換入換出的進(jìn)程也不一.因此內(nèi)存中很容易產(chǎn)生大量不連接的空閑內(nèi)存.需要對(duì)這些內(nèi)存進(jìn)行記錄.以便下次再有進(jìn)程交換時(shí)使用.

使用位圖管理.把每個(gè)小塊內(nèi)存標(biāo)記為1位.0表示空閑,1表示占用

使用鏈表管理.把空閑內(nèi)存和占用內(nèi)存都看成節(jié)點(diǎn).用鏈表串起來(lái),p表示進(jìn)程,h表示空閑.進(jìn)程的交換可以通過(guò)移動(dòng)鏈表來(lái)實(shí)現(xiàn).如下是兩種方式.

image-20191216202125556

虛擬內(nèi)存技術(shù)

內(nèi)存交換技術(shù)的最大問(wèn)題是.現(xiàn)在程序的容量遠(yuǎn)大于內(nèi)存的容量.這就限制了程序的大小.

虛擬內(nèi)存的目的,是把程序中的地址和真正的物理地址解綁.而通過(guò)一層映射關(guān)系來(lái)轉(zhuǎn)換.這樣可以給進(jìn)程提供大的一致的和私有的地址空間.程序就不必關(guān)心實(shí)際上執(zhí)行的地址是哪里. 而且程序可以部分加載到內(nèi)存中,部分在磁盤(pán)里.只有在需要時(shí)才加載到內(nèi)存.并把用完的換出來(lái).這需要把內(nèi)存和程序都分成多個(gè)塊.按塊來(lái)加載移出.'

分頁(yè)

分頁(yè)就是把內(nèi)存和磁盤(pán)分為同樣容量的空間.內(nèi)存中交頁(yè)面.磁盤(pán)中叫頁(yè)框.通常為4kb,然后內(nèi)存和磁盤(pán)以頁(yè)為單位進(jìn)行數(shù)據(jù)交換.內(nèi)存中找不到需要的頁(yè)時(shí),觸發(fā)缺頁(yè)中斷.通過(guò)系統(tǒng)把該頁(yè)讀到內(nèi)存中,更行映射表.

映射表管理內(nèi)存頁(yè)和磁盤(pán)頁(yè)的對(duì)應(yīng)關(guān)系.每個(gè)頁(yè)的記錄是一條頁(yè)表項(xiàng).頁(yè)表項(xiàng)中有保護(hù)位,指出頁(yè)的權(quán)限(可讀,可寫(xiě),可執(zhí)行), 修改位記錄該頁(yè)是否在內(nèi)存中被修改過(guò).如果修改過(guò),換出時(shí)要寫(xiě)回磁盤(pán).沒(méi)有修改過(guò)可以直接丟棄(沒(méi)有修改意味著內(nèi)存的數(shù)據(jù)和磁盤(pán)是一致的). 訪問(wèn)位記錄該頁(yè)被CPU訪問(wèn)的情況,用來(lái)在內(nèi)存不足時(shí)通過(guò)算法把不常訪問(wèn)的頁(yè)換出內(nèi)存.

因?yàn)樾枰褍?nèi)存中的頁(yè)換出到磁盤(pán).在加載指定的頁(yè).這里有一個(gè)算法的選擇.大概記錄下.

image-20191216203850672

分頁(yè)在內(nèi)存中的效果.需要看到.每次進(jìn)程換入換出的物理地址不一定是一樣的.每個(gè)進(jìn)程有自己的進(jìn)程頁(yè)表,通過(guò)頁(yè)表.導(dǎo)致虛擬地址總能映射到該進(jìn)程正確的物理地址.

image-20191217212152594
image-20191217212205160

共享庫(kù)

目前常規(guī)的做法是一個(gè)程序.具有程序的地址空間和數(shù)據(jù)的地址空間,這兩個(gè)空間有自己獨(dú)立的映射表.分別進(jìn)行內(nèi)存映射.而對(duì)于系統(tǒng)程序和庫(kù)文件.采用共享的方式實(shí)現(xiàn).多個(gè)進(jìn)程共享一份庫(kù)程序的地址空間,但是每個(gè)進(jìn)程有自己的數(shù)據(jù)空間.也就是對(duì)與共享庫(kù), 代碼共享,數(shù)據(jù)獨(dú)立.

image-20191216204218263
image-20191214121521230

分段

因?yàn)槌绦蚩赡茉谶\(yùn)行過(guò)程中占用內(nèi)存越來(lái)越多.系統(tǒng)提供多個(gè)互相獨(dú)立的稱為段的地址空間.每個(gè)段都從0地址開(kāi)始增長(zhǎng),且段的長(zhǎng)度可以在運(yùn)行期間動(dòng)態(tài)改變.每個(gè)段都是獨(dú)立的. 通過(guò)一個(gè)段號(hào)和一個(gè)段內(nèi)地址來(lái)定位到特定的位置.段是一個(gè)邏輯實(shí)體.是對(duì)程序員可見(jiàn)的.而頁(yè)是物理實(shí)體.是對(duì)程序員不可見(jiàn).

因?yàn)槊總€(gè)段獨(dú)立.因此每個(gè)段如果改版后重新編譯,即使比上一個(gè)版本變大了(也就是地址變化了),也不會(huì)影響別的段.

一個(gè)程序的各種段.

image-20191216204939518

分段和分頁(yè)結(jié)合

image-20191216205743827

段號(hào)和段表指針找到段號(hào).通過(guò)段號(hào)在段表中拿到數(shù)據(jù)和頁(yè)號(hào)組成頁(yè)表中的索引,在得到頁(yè)框號(hào).頁(yè)框好和偏移量形成物理地址.

image-20191217212948303

查詢辦法如下.因?yàn)橛袛嗟母拍?因此也就多了一個(gè)段號(hào)和描述符段的映射表.也就是要兩次映射關(guān)系.這增加了復(fù)雜度.

image-20191216205837574

分段和分頁(yè)的比較

image-20191216205156513
image-20191217212609395

虛擬尋址

image-20191214124310647

虛擬尋址就是CPU生成的地址需要通過(guò)一個(gè)cpu上的硬件MMU進(jìn)行轉(zhuǎn)翻譯,才能對(duì)應(yīng)真正的物理地址.CPU以為他生產(chǎn)的是物理地址,其實(shí)不是.

虛擬內(nèi)存

虛擬內(nèi)存就是對(duì)時(shí)間磁盤(pán)的緩存. 虛擬內(nèi)存的大小單位是虛擬頁(yè),物理內(nèi)存的大小單位是物理頁(yè).虛擬頁(yè)和物理頁(yè)的大小相等.

image-20191214124758710

緩存就是利用程序的局部性原理.把CPU要執(zhí)行的一小塊數(shù)據(jù)和指令.放入高速,容量小的高級(jí)緩存中,其余局部性外的數(shù)據(jù)和指令放在低速容量大的存儲(chǔ)中,CPU依次向下執(zhí)行,不斷有新的數(shù)據(jù)和指令加入到高級(jí)緩存中,然后把執(zhí)行過(guò)的數(shù)據(jù)和指令移出到低速存儲(chǔ)中.這就模擬處了CPU執(zhí)行的數(shù)據(jù)和指令一直在高速的高級(jí)緩存中執(zhí)行的效果.

這里就涉及到了一個(gè)虛擬頁(yè)到實(shí)際物理頁(yè)的轉(zhuǎn)化. 通常操作系統(tǒng)都是用一個(gè)映射表來(lái)保存這種映射關(guān)系的.這個(gè)映射表叫做頁(yè)表.通過(guò)一個(gè)有效為來(lái)標(biāo)識(shí),改虛擬頁(yè)對(duì)應(yīng)的物理頁(yè)是否在內(nèi)存中.如果在.就可以直接使用這個(gè)內(nèi)存中的頁(yè).如果不在,就表示該虛擬頁(yè)對(duì)應(yīng)的物理頁(yè)是在磁盤(pán)上.就要先把物理頁(yè)讀取到內(nèi)存中,然后更新頁(yè)表的這個(gè)條目,然后從新查詢這個(gè)條目.這次就發(fā)現(xiàn)在內(nèi)存中了.就可以使用

image-20191214125956952

對(duì)于虛擬頁(yè)中來(lái)說(shuō).他對(duì)于的物理頁(yè)可能在內(nèi)存中,也可能在磁盤(pán)中.物理頁(yè)號(hào)或者磁盤(pán)地址,是用來(lái)結(jié)合虛擬地址形成真正的物理地址使用的.

缺頁(yè)

虛擬頁(yè)對(duì)應(yīng)的物理頁(yè)不在內(nèi)存中,這就要缺頁(yè).需要把對(duì)應(yīng)的物理頁(yè)從磁盤(pán)中讀取到內(nèi)存中.并更新頁(yè)表的條目?

image-20191216204513613
image-20191214130330696

內(nèi)存分配

image-20191214130611087

實(shí)際上操作系統(tǒng)為每個(gè)進(jìn)程都分配了獨(dú)立頁(yè)表.因此每個(gè)進(jìn)程獨(dú)享一個(gè)獨(dú)立的虛擬空間.有一下好處

  • 簡(jiǎn)化程序鏈接過(guò)程. 獨(dú)立的地址空間,可以讓程序有標(biāo)準(zhǔn)的內(nèi)存結(jié)構(gòu).比如程序都從0x4000開(kāi)始.數(shù)據(jù)都從0x8000開(kāi)始.這樣.不同的程序地址相同.但是這個(gè)只是虛擬地址相同(實(shí)際上可能a的程序從0x1111開(kāi)始,b程序從0x9999開(kāi)始,但是這對(duì)程序是不可見(jiàn)的).
  • 簡(jiǎn)化共享. 共享文件和系統(tǒng)庫(kù),可以只在內(nèi)存中保留一份,然后通過(guò)映射到不同進(jìn)程的不同虛擬地址,這樣可以共享一份系統(tǒng)庫(kù)的代碼.然后每個(gè)進(jìn)程有自己的數(shù)據(jù)存儲(chǔ)就可以了
  • 簡(jiǎn)化加載. 加載器加載可執(zhí)行文件時(shí),把.text和.data的代碼和數(shù)據(jù)段分配虛擬地址,并標(biāo)記為沒(méi)有內(nèi)存緩存,這樣就可以在執(zhí)行到代碼和數(shù)據(jù)的時(shí)候通過(guò)缺頁(yè),從磁盤(pán)中加載進(jìn)來(lái).這就構(gòu)成了動(dòng)態(tài)的載入.
  • 簡(jiǎn)化內(nèi)存分配. 這使得一個(gè)程序不需要全部加載到內(nèi)存中才開(kāi)始執(zhí)行,而是執(zhí)行到那里加載哪里.就可以在內(nèi)存中運(yùn)行多個(gè)程序.也可以運(yùn)行比內(nèi)存空間還打的程序.

地址翻譯

地址翻譯就是把虛擬地址翻譯成物理地址,這需要通過(guò)上文的頁(yè)表的數(shù)據(jù)來(lái)實(shí)現(xiàn)

image-20191214131719766

因?yàn)轫?yè)表中的條目.是虛擬地址的映射,這是經(jīng)常變動(dòng)的.虛擬地址的高位部分是虛擬頁(yè)號(hào),通過(guò)虛擬頁(yè)號(hào)可以找到頁(yè)表中對(duì)應(yīng)的物理頁(yè)號(hào).物理頁(yè)號(hào)和虛擬地址的后半部分的虛擬頁(yè)偏移量構(gòu)成真正的物理地址,總結(jié)起來(lái)就是頁(yè)偏移量是固定的 .但是虛擬頁(yè)對(duì)應(yīng)哪個(gè)物理頁(yè)是要靠表來(lái)查出.當(dāng)有效位為真時(shí),組成的物理地址指向內(nèi)存中的緩存頁(yè).有效為為假時(shí).指向的是磁盤(pán)的物理地址,需要把這個(gè)頁(yè)換如內(nèi)存中.

具體執(zhí)行過(guò)程如下

VA (virtual addreaa)是虛擬地址. PTEA(page table Entry address) 是頁(yè)表映射條目的地址,表示要拿哪個(gè)頁(yè)表映射條目.pte(page table entry)是頁(yè)表映射條目,也就是虛擬地址和物理地址的映射關(guān)系,pa 是物理地址(physical address),也就是CPU真正要獲取數(shù)據(jù)或指令的地址,通過(guò)pa拿到真正的數(shù)據(jù).

image-20191214132328677
image-20191214132339851

可以看到.MMU不保存頁(yè)表結(jié)構(gòu).因此他要先查詢頁(yè)表?xiàng)l目,在翻譯成物理地址.為了加快這一過(guò)程.又在MMU中加入了一個(gè)小的緩存結(jié)構(gòu)TLB(tarnslation lookaside buffer),tlb就是對(duì)頁(yè)表的局部換從,因此以后可以先從TBL中查詢頁(yè)表?xiàng)l目,在經(jīng)過(guò)MMU生成物理地址,在從內(nèi)存或磁盤(pán)中獲取. TLB的容量遠(yuǎn)小于內(nèi)存中的頁(yè)表大小.因此TLB也需要實(shí)時(shí)更新.

image-20191214133443892

多級(jí)頁(yè)面

因?yàn)閮?nèi)存和磁盤(pán)的容量不斷增大.為了提高頁(yè)表的查找速度,把頁(yè)表分成了多級(jí)頁(yè)表.也就是高層頁(yè)表中的條目指向底層頁(yè)表.然后多次讀取多個(gè)頁(yè)表后.在最底層的頁(yè)表中拿到對(duì)應(yīng)的物理地址.

image-20191214133815485

記住.這種多級(jí)頁(yè)表.只有最后級(jí)頁(yè)表中才存儲(chǔ)物理地址的頁(yè)號(hào)信息.

image-20191214133827913

linux虛擬內(nèi)存系統(tǒng)

image-20191214135210854

可以看到.每個(gè)進(jìn)程的虛擬內(nèi)存中.都有一部分內(nèi)核虛擬內(nèi)存被映射進(jìn)該進(jìn)程.內(nèi)核虛擬內(nèi)存的某些區(qū)域被映射到所有進(jìn)程共享的物理頁(yè)面.例如每個(gè)進(jìn)程共享內(nèi)核的代碼和數(shù)據(jù).而內(nèi)核中還有一些屬于進(jìn)程獨(dú)有的數(shù)據(jù).這些就是該進(jìn)程的上下文環(huán)境.

linux把虛擬內(nèi)存組成成多個(gè)連續(xù)的內(nèi)存片段或區(qū)域.一個(gè)區(qū)域就是已分配的連續(xù)的虛擬內(nèi)存片.通過(guò)一個(gè)數(shù)據(jù)結(jié)構(gòu)記錄那些已分配的虛擬存儲(chǔ).而不記錄沒(méi)有分配的空間.這就允許虛擬地址空間中有間隙.(也就是說(shuō)虛擬地址也不一定都是完全連在一起的,而是某個(gè)結(jié)構(gòu)中虛擬地址是連續(xù)的.)

image-20191214135820058

這是一個(gè)鏈表結(jié)構(gòu),他抽象了進(jìn)程的代碼和數(shù)據(jù)和共享庫(kù)的內(nèi)容.也就是這個(gè)結(jié)構(gòu)只記錄該進(jìn)程使用了哪些地址空間.具有什么權(quán)限.而不管這個(gè)空間存的是數(shù)據(jù)還是代碼還是系統(tǒng)庫(kù).

image-20191214135953314

內(nèi)存映射

內(nèi)存映射就是虛擬內(nèi)存和磁盤(pán)上的 對(duì)象關(guān)聯(lián)起來(lái),用來(lái)初始化虛擬內(nèi)存區(qū)域的內(nèi)容.這種技術(shù)可以實(shí)現(xiàn)很多功能.

  • 共享對(duì)象. 可以實(shí)現(xiàn)多個(gè)進(jìn)程映射到同一物理區(qū)域,這樣一個(gè)進(jìn)程對(duì)物理區(qū)域的改變,其他進(jìn)程也能知道變化,這為進(jìn)程間通訊提供了一種方式
image-20191214141212086
  • 私有對(duì)象 私有對(duì)象也可能是一個(gè)物理內(nèi)存被多個(gè)進(jìn)程所映射了.但是不同進(jìn)程對(duì)改私有區(qū)域的改動(dòng)只會(huì)是自己的區(qū)域可見(jiàn).別的進(jìn)程看不見(jiàn).這就要求每個(gè)進(jìn)程在寫(xiě)私有區(qū)域時(shí)寫(xiě)到額外的空間并只有自己持有.開(kāi)始時(shí)與共享對(duì)象一項(xiàng),所有進(jìn)程指向同一區(qū)域,然后A進(jìn)程寫(xiě)改私有對(duì)象時(shí),會(huì)把要寫(xiě)的頁(yè)在內(nèi)存中創(chuàng)建一個(gè)新的副本.把數(shù)據(jù)在復(fù)制進(jìn)去.這副本只有進(jìn)程A有映射關(guān)系.這叫寫(xiě)時(shí)復(fù)制.讀時(shí)無(wú)所謂.
image-20191214141822512

寫(xiě)時(shí)復(fù)制就是fork函數(shù)的實(shí)現(xiàn)原理.fork完成后.父進(jìn)程和子進(jìn)程共享原來(lái)的內(nèi)存.當(dāng)子進(jìn)程或者父進(jìn)程要執(zhí)行寫(xiě)操作時(shí).觸發(fā)寫(xiě)時(shí)復(fù)制,然后兩個(gè)進(jìn)程就有了自己獨(dú)立的數(shù)據(jù).

計(jì)算機(jī)結(jié)構(gòu)

image-20191214172220877

文件系統(tǒng)

文件

文件是一種抽象.提供了對(duì)磁盤(pán)上信息的增刪改查.并讓用戶忽略底層細(xì)節(jié).通過(guò)拓展名可以表示一些信息,執(zhí)行不同操作.

文件通常分為文件和目錄.目錄中包含其他目錄或文件.文件的訪問(wèn)方式是順序或者隨機(jī).順序訪問(wèn)必須從前向后訪問(wèn),不可以跳過(guò).隨機(jī)訪問(wèn)仍以跳轉(zhuǎn)訪問(wèn)文件的任何位置.

image-20191216211331078

文件操作

create 創(chuàng)建,delete 刪除,open 打開(kāi),close 關(guān)閉,read 讀,write 寫(xiě),append 追加(只在文件末尾寫(xiě)),seek 隨機(jī)訪問(wèn)文.rename 重命名文件.get/setattribute,設(shè)置文件屬性

目錄操作

create 創(chuàng)建,delete刪除,opendir.打開(kāi)目錄.closedir關(guān)閉目錄.readdir讀取目錄.rename 重命名.link 把某文件鏈接到另一處.這樣兩處都可以修改這個(gè)文件. unlink 解出鏈接.

文件的結(jié)構(gòu)

image-20191216212124437

mbr是主引導(dǎo)記錄,用來(lái)引導(dǎo)計(jì)算機(jī)加載磁盤(pán).分區(qū)表記錄磁盤(pán)所有分區(qū)的開(kāi)始和結(jié)束.每個(gè)分區(qū)開(kāi)頭都是引導(dǎo)塊.引導(dǎo)塊中可以裝在操作系統(tǒng).超級(jí)快包含文件系統(tǒng)的所有信息.空閑空間管理文件系統(tǒng)的空閑塊信息.i節(jié)點(diǎn)連接文件系統(tǒng)中所有文件,每個(gè)文件1個(gè)i節(jié)點(diǎn),

文件分配

文件分配表法

image-20191216212627661

每個(gè)文件由多個(gè)文件塊構(gòu)成.然后通過(guò)鏈表連接在一起.但是鏈表的隨機(jī)訪問(wèn)比較慢.因此在內(nèi)存中保存一個(gè)文件分配表.記錄文件塊的連接關(guān)系.比如A文件從物理塊4開(kāi)始,指向物理塊7,物理塊7的位置又指向2,因此a的鏈表是 4-7-2-10-12(最后一-1結(jié)束.)這個(gè)方式的缺點(diǎn)是整個(gè)表要放在內(nèi)存中.因此又提出了改進(jìn)方法

i節(jié)點(diǎn)法

每個(gè)節(jié)點(diǎn)賦值一個(gè)i節(jié)點(diǎn)的數(shù)據(jù)結(jié)構(gòu).記錄所以改文件的塊,只有該文件打開(kāi),才把i節(jié)點(diǎn)加載到內(nèi)存中.

image-20191217194425568

i節(jié)點(diǎn)的最好一個(gè)地址指向額外的磁盤(pán)塊,這樣就不會(huì)限制文件的大小.下圖是unix的i節(jié)點(diǎn),他最后幾個(gè)塊指向間接塊.這個(gè)樣可以使文件的容量變大很多

image-20191217195522307

虛擬文件系統(tǒng)

將多中文件系統(tǒng)統(tǒng)一成一個(gè)有序的結(jié)構(gòu),抽象所有文件系統(tǒng)的公共部分,作為虛擬文件系統(tǒng).在虛擬文件系統(tǒng)下一層是不同系統(tǒng)的具體實(shí)現(xiàn)

image-20191217194510614

vfs(虛擬文件系統(tǒng))有兩層接口,上層提供給用戶進(jìn)程,下次給實(shí)際的文件系統(tǒng).當(dāng)一個(gè)文件系統(tǒng)要加載到vfs上時(shí),需要該系統(tǒng)向vfs注冊(cè),提供一個(gè)包含vfs需要的函數(shù)(打開(kāi)關(guān)閉等)的列表.以后vfs就可以通過(guò)這列表來(lái)調(diào)用該文件操作系統(tǒng).而對(duì)用戶進(jìn)程.則不管接入的是什么文件系統(tǒng).都是統(tǒng)一調(diào)用vfs提供的接口.

io

io設(shè)備分塊設(shè)備和字符設(shè)備.塊設(shè)備把信息存儲(chǔ)在固定大小的快中,每個(gè)塊有自己地址.可以獨(dú)立讀寫(xiě).字符設(shè)備以字符為單位發(fā)生或接受一個(gè)字符流.不可尋址,只能按順序讀寫(xiě). 磁盤(pán)是塊設(shè)備.打印機(jī)是字符設(shè)備.

io通信方式

io設(shè)備分為機(jī)械部件和電子部件.電子部件叫控制器,每個(gè)控制器有幾個(gè)寄存器與CPU通信.有些設(shè)備還有緩沖區(qū).控制器負(fù)責(zé)與CPU溝通.控制io設(shè)備.因此需要與io設(shè)備通信.有兩種方式

image-20191217214021146

io端口

每個(gè)寄存器被分配一個(gè)io端口號(hào),CPU通過(guò)特殊指令與io端口通信.

內(nèi)存映射io

把控制器映射到內(nèi)存中,不需要特殊的指令.控制器具有唯一的地址.CPU通過(guò)這個(gè)地址與io設(shè)備通信

控制器是硬件設(shè)備.而且不同的io設(shè)備有不同的控制器.因此加入了設(shè)備驅(qū)動(dòng)程序這一層.設(shè)備驅(qū)動(dòng)同硬件綁定, 一個(gè)硬件在不同操作系統(tǒng)平臺(tái)有不同的驅(qū)動(dòng)程序.驅(qū)動(dòng)程序用來(lái)控制io硬件.設(shè)備驅(qū)動(dòng)程序運(yùn)行在內(nèi)核態(tài).不允許用戶隨便執(zhí)行.

DMA技術(shù)

內(nèi)存和io設(shè)備直接通信,在結(jié)束后通知CPU的方法.這樣不需要CPU實(shí)時(shí)進(jìn)行處理.但是也需要占用總線傳輸數(shù)據(jù).

image-20191217201118600
  1. CPU對(duì)DMA控制器的寄存器對(duì)他編程,指明把什么數(shù)據(jù)從那送到那
  2. DMA控制器向磁盤(pán)發(fā)送命令.通知磁盤(pán)讀數(shù)據(jù)到他內(nèi)部的緩沖區(qū).并校驗(yàn)數(shù)據(jù)
  3. DMA控制器在總線上發(fā)請(qǐng)求給磁盤(pán)控制器來(lái)發(fā)起DMA傳送
  4. 磁盤(pán)把他內(nèi)部緩沖區(qū)的數(shù)據(jù)傳輸?shù)絻?nèi)充中.因?yàn)榇疟P(pán)是以塊為單位讀寫(xiě).所以3.4步會(huì)一直重復(fù)直到數(shù)據(jù)寫(xiě)完
  5. DMA發(fā)出完成的中斷信號(hào)給CPU.通知傳輸完成,此時(shí)數(shù)據(jù)在內(nèi)存中.
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末仔拟,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子宿稀,更是在濱河造成了極大的恐慌吐葱,老刑警劉巖冰悠,帶你破解...
    沈念sama閱讀 216,402評(píng)論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件膀曾,死亡現(xiàn)場(chǎng)離奇詭異瘫筐,居然都是意外死亡旱眯,警方通過(guò)查閱死者的電腦和手機(jī)耕魄,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén)画恰,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人吸奴,你說(shuō)我怎么就攤上這事允扇。” “怎么了则奥?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,483評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵考润,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我逞度,道長(zhǎng)额划,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,165評(píng)論 1 292
  • 正文 為了忘掉前任档泽,我火速辦了婚禮俊戳,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘馆匿。我一直安慰自己抑胎,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,176評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布渐北。 她就那樣靜靜地躺著阿逃,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上恃锉,一...
    開(kāi)封第一講書(shū)人閱讀 51,146評(píng)論 1 297
  • 那天搀菩,我揣著相機(jī)與錄音,去河邊找鬼破托。 笑死肪跋,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的土砂。 我是一名探鬼主播州既,決...
    沈念sama閱讀 40,032評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼萝映!你這毒婦竟也來(lái)了吴叶?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 38,896評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤序臂,失蹤者是張志新(化名)和其女友劉穎蚌卤,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體贸宏,經(jīng)...
    沈念sama閱讀 45,311評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡造寝,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,536評(píng)論 2 332
  • 正文 我和宋清朗相戀三年磕洪,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了吭练。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,696評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡析显,死狀恐怖鲫咽,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情谷异,我是刑警寧澤分尸,帶...
    沈念sama閱讀 35,413評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站歹嘹,受9級(jí)特大地震影響箩绍,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜尺上,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,008評(píng)論 3 325
  • 文/蒙蒙 一材蛛、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧怎抛,春花似錦卑吭、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春掷邦,著一層夾襖步出監(jiān)牢的瞬間白胀,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,815評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工抚岗, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留纹笼,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,698評(píng)論 2 368
  • 正文 我出身青樓苟跪,卻偏偏與公主長(zhǎng)得像廷痘,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子件已,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,592評(píng)論 2 353