自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

操作系統(tǒng)是如何一步步發(fā)明虛擬內(nèi)存的?

系統(tǒng) 其他OS
面對內(nèi)存不足的問題,你開始思考,既然內(nèi)存一次性裝不下大型程序,那么為什么不把這個大型程序拆開了、用到哪些就裝哪些呢?

那時引以為傲的System/360大型機(jī)雖然配備了豪華的256KB物理內(nèi)存(價格相當(dāng)于今天的數(shù)百萬美元),但在引入多進(jìn)程后內(nèi)存相關(guān)的問題開始出現(xiàn),因?yàn)槎鄠€進(jìn)程可以同時運(yùn)行在內(nèi)存中。

你面臨的核心問題是:如何保證多進(jìn)程能夠高效共享有限的物理內(nèi)存?

最初的嘗試:固定分區(qū)

你的第一個嘗試是最直觀的方法,將物理內(nèi)存劃分為幾個固定大小的區(qū)域,每個區(qū)域分配給一個程序:

圖片圖片

這就是所謂的固定分區(qū)(Fixed Partitioning),這個想法很簡單,你很快實(shí)現(xiàn)了這個機(jī)制:

// 固定分區(qū)內(nèi)存管理的簡單實(shí)現(xiàn)
struct memory_partition {
    void* start_address;      // 分區(qū)起始地址
    size_t size;             // 分區(qū)大小
    bool is_occupied;        // 是否被占用
    int process_id;          // 占用進(jìn)程ID
};

這個簡單的分區(qū)系統(tǒng)確實(shí)解決了一些問題。它允許多個程序同時駐留在內(nèi)存中,并提供了基本的內(nèi)存隔離。然而,它很快就暴露出了嚴(yán)重的缺陷。

問題出在內(nèi)存利用率上:一個只需要10KB內(nèi)存的小程序占用了整個64KB的分區(qū),而一個需要70KB的程序卻無法運(yùn)行,因?yàn)闆]有任何一個分區(qū)足夠大,盡管系統(tǒng)中空閑內(nèi)存超過了70KB!

圖片

你意識到,固定分區(qū)雖然簡單,但極其浪費(fèi)內(nèi)存資源。

它無法適應(yīng)程序大小的變化,也無法解決運(yùn)行大型程序的問題。

這個方案本質(zhì)就是吃大鍋飯,不管你可執(zhí)行程序本身有多大都給你固定內(nèi)存,打破大鍋飯的最佳方法就是按勞分配。

動態(tài)分區(qū):按需分配

既然是按勞分配那就不能預(yù)先劃分內(nèi)存,而是根據(jù)程序的實(shí)際需求動態(tài)分配內(nèi)存塊,用多少給多少:

// 動態(tài)分區(qū)內(nèi)存管理
struct memory_block {
    void* start_address;      // 內(nèi)存塊起始地址
    size_t size;             // 內(nèi)存塊大小
    bool is_free;            // 是否空閑
    struct memory_block* next; // 鏈表中的下一個塊
};

struct memory_block* free_list; // 空閑內(nèi)存塊鏈表

這就是你在數(shù)據(jù)結(jié)構(gòu)課上學(xué)到的鏈表。

動態(tài)分區(qū)確實(shí)提高了內(nèi)存利用率,程序可以獲得剛好滿足其需求的內(nèi)存量,這種內(nèi)存分配方法開始流行起來。

然而,隨著系統(tǒng)運(yùn)行時間的增長,大量用戶開始反饋物理內(nèi)存很快耗盡導(dǎo)致程序崩潰,一通debug后你發(fā)現(xiàn)了問題:內(nèi)存碎片。

只需要幾周的運(yùn)行,系統(tǒng)中就會出現(xiàn)了大量的小內(nèi)存塊,它們分散在各處,雖然總和足夠大,但沒有一個連續(xù)的塊能滿足新程序的需求。

更糟糕的是,即使使用動態(tài)分區(qū),仍然無法運(yùn)行那些需要超過物理內(nèi)存總量的程序。

因?yàn)樵?0世紀(jì)60-80年代,雖然計算機(jī)物理內(nèi)存有限(如KB級別),但程序規(guī)模卻在逐漸增大(如大型科學(xué)計算、數(shù)據(jù)庫系統(tǒng)),這是一個根本性的限制,你需要一種全新的思路...

覆蓋技術(shù):程序員的自我管理

面對內(nèi)存不足的問題,你開始思考,既然內(nèi)存一次性裝不下大型程序,那么為什么不把這個大型程序拆開了、用到哪些就裝哪些呢?

看上去好像能解決問題,你進(jìn)一步思考,程序其實(shí)可以被劃分為多個獨(dú)立的功能模塊,一些核心的模塊可能需要始終駐留在內(nèi)存(如主控制邏輯、核心函數(shù)),而非核心的功能模塊可以按需動態(tài)加載到共享內(nèi)存區(qū)域,覆蓋前一個模塊。

假設(shè)可執(zhí)行程序A劃分為一個核心模塊和4個功能模塊,那么當(dāng)需要運(yùn)行模塊1時就把模塊1加載到共享內(nèi)存區(qū)域,當(dāng)需要運(yùn)行模塊2時就把模塊2加載到共享內(nèi)存中覆蓋掉原來的模塊1:

圖片圖片

這樣就能實(shí)現(xiàn)在有限的物理內(nèi)存中運(yùn)行超大程序的目的,這就是早期操作系統(tǒng)中的"覆蓋技術(shù)"(Overlay)。

這種方法要求程序員手動將程序分割成多個模塊,并在運(yùn)行時根據(jù)需要將不同模塊加載到同一塊內(nèi)存區(qū)域。

// 程序員使用覆蓋技術(shù)的偽代碼
void main() {
    // 主模塊始終在內(nèi)存中
    
    // 需要模塊A時
    load_module("module_A", OVERLAY_REGION);
    execute_module_A();
    
    // 需要模塊B時,覆蓋同一內(nèi)存區(qū)域
    load_module("module_B", OVERLAY_REGION);
    execute_module_B();
    
    // 再次需要模塊A時
    load_module("module_A", OVERLAY_REGION);
    execute_module_A_again();
}

覆蓋技術(shù)確實(shí)突破了物理內(nèi)存限制,可以在有限的物理內(nèi)存上運(yùn)行大型程序,是一種非常聰明的方法。

但它有嚴(yán)重的缺點(diǎn):

  1. 程序員必須手動管理內(nèi)存,這極其復(fù)雜且容易出錯
  2. 程序必須預(yù)先知道哪些模塊可以共享內(nèi)存區(qū)域
  3. 頻繁的模塊加載會導(dǎo)致性能下降

這讓你開始認(rèn)識到:內(nèi)存管理太重要了,絕不能完全依賴程序員自己手動管理。

因此你需要一個系統(tǒng)級的解決方案,能夠自動管理內(nèi)存,對程序員透明,同時允許程序使用超過物理內(nèi)存的地址空間,這就是后來的虛擬內(nèi)存技術(shù)。

責(zé)任編輯:武曉燕 來源: 碼農(nóng)的荒島求生
相關(guān)推薦

2025-04-03 01:45:00

2025-03-28 09:39:15

CPU指令信號

2024-09-30 09:56:59

2024-11-11 10:28:33

操作系統(tǒng)Unix系統(tǒng)

2024-09-12 10:04:06

內(nèi)存程序系統(tǒng)

2025-04-09 08:45:00

操作系統(tǒng)進(jìn)程線程

2018-07-13 15:36:52

2015-07-27 16:06:16

VMware Thin虛擬化

2024-06-27 08:30:36

內(nèi)存擴(kuò)容堆區(qū)

2024-08-30 08:30:29

CPU操作系統(tǒng)寄存器

2017-01-19 21:08:33

iOS路由構(gòu)建

2017-12-25 11:50:57

LinuxArch Linux

2024-08-06 09:29:54

程序機(jī)器指令字符串

2019-03-05 14:09:27

Docker存儲容器

2019-07-09 15:23:22

Docker存儲驅(qū)動

2018-12-24 10:04:06

Docker存儲驅(qū)動

2019-04-01 10:15:02

2010-03-04 16:28:17

Android核心代碼

2017-01-06 15:13:25

LinuxVim源代碼

2016-11-02 18:54:01

javascript
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號