實體地址和邏輯位址(或稱虛擬位址)的概念。
使用者程式看不見真正的實體地址。使用者只生成邏輯位址,且認為程序的位址空間為0到max。實體地址範圍從r+0到r+max,r為基位址,位址對映-將程式位址空間中使用的邏輯位址變換成記憶體中的實體地址的過程。由記憶體管理單元(mmu)來完成。
fork()會產生乙個和父程序完全相同的子程序,但子程序在此後多會exec系統呼叫,出於效率考慮,linux中引入了「寫時複製「技術,也就是只有程序空間的各段的內容要發生變化時,才會將父程序的內容複製乙份給子程序。在fork之後exec之前兩個程序用的是相同的物理空間(記憶體區),子程序的**段、資料段、堆疊都是指向父程序的物理空間,也就是說,兩者的虛擬空間不同,但其對應的物理空間是同乙個。
當父子程序中有更改相應段的行為發生時,再為子程序相應的段分配物理空間,如果不是因為exec,核心會給子程序的資料段、堆疊段分配相應的物理空間(至此兩者有各自的程序空間,互不影響),而**段繼續共享父程序的物理空間(兩者的**完全相同)。而如果是因為exec,由於兩者執行的**不同,子程序的**段也會分配單獨的物理空間。
fork時子程序獲得父程序資料空間、堆和棧的複製,所以變數的位址(當然是虛擬位址)也是一樣的。
每個程序都有自己的虛擬位址空間,不同程序的相同的虛擬位址顯然可以對應不同的實體地址。因此位址相同(虛擬位址)而值不同沒什麼奇怪。
「寫時複製」的具體過程是這樣的:
fork子程序完全複製父程序的棧空間,也複製了頁表,但沒有複製物理頁面,所以這時虛擬位址相同,實體地址也相同,但是會把父子共享的頁面標記為「唯讀」(類似mmap的private的方式)
如果父子程序一直對這個頁面是同乙個頁面,直到其中任何乙個程序要對共享的頁面「寫操作」,這時核心會複製乙個物理頁面給這個程序使用,同時修改頁表。而把原來的唯讀頁面標記為「可寫」,留給另外乙個程序使用。
這就是所謂的「寫時複製」。
正因為fork採用了這種寫時複製的機制,所以fork出來子程序之後,父子程序哪個先排程呢?
假定父程序malloc的指標指向0x12345678, fork 後,子程序中的指標也是指向0x12345678,但是這兩個位址都是虛擬記憶體位址 (virtual memory),經過記憶體位址轉換後所對應的 實體地址是不一樣的。所以兩個進城中的這兩個位址相互之間沒有任何關係。
(注:但實際上,linux為了提高 fork 的效率,採用了 copy-on-write 技術,fork後,這兩個虛擬位址實際上指向相同的實體地址(記憶體頁),只有任何乙個程序試圖修改這個虛擬位址裡的內容前,兩個虛擬位址才會指向不同的實體地址(新的實體地址的內容從原實體地址中複製得到))
fork到底做了什麼?
在 linux 中 fork 是乙個非常重要的函式,它從乙個已經存在的程序中建立出了乙個新程序,這個新程序稱為子程序,而原程序稱為父程序。對於很多初學者來說,這是最不能理解的。的確,這只能說是看起來像,因為從彙編的層面就已經決定了棧的壓棧和出棧是成對出現的,乙個函式永遠只會返回一次。fork 函式的...
析構函式到底都做了什麼
析構函式釋放物件所使用的資源,並且銷毀物件的非static資料成員。析構函式是類的乙個成員函式,名字有波浪號接類名構成。沒有返回值,也不接受引數,同時由於析構函式不接受引數,因此它不能過載,所以任何乙個類都只具有乙個析構函式。析構函式具有乙個函式體和乙個析構部分。首先執行函式體,然後執行析構部分,來...
你到底做了什麼
從1月份 一直到現在,有沒有人問過自己,你到底做過了什麼,又做成了什麼。已經有4個月沒有碰過所謂的課本,一直也提不起學習的興趣,不過我做事一般不會後悔,我沒有學習,雖然這並不對,但是起碼我並沒有浪費自己的時間,我去玩也好,我睡覺也好,我度過了別人所沒有的生活,我也交往了新的朋友,新的老師,雖然與許多...