如果你的電腦上安裝了QQ,你希望和好友聊天柑土,會雙擊QQ圖標蜀肘,打開QQ軟件,輸入賬號和密碼稽屏,然后登錄就可以了扮宠。
那么,QQ是怎么運行起來的呢狐榔?
首先坛增,有一點你要明確,你安裝的QQ軟件是保存在硬盤中的薄腻。
雙擊QQ圖標收捣,操作系統(tǒng)就會知道你要運行這個軟件,它會在硬盤中找到你安裝的QQ軟件庵楷,將數(shù)據(jù)(安裝的軟件本質上就是很多數(shù)據(jù)的集合)復制到內存罢艾。對!就是復制到內存尽纽!QQ不是在硬盤中運行的咐蚯,而是在內存中運行的。
為什么呢弄贿?因為內存的讀寫速度比硬盤快很多春锋。
對于讀寫速度,內存 > 固態(tài)硬盤 > 機械硬盤挎春。機械硬盤是靠電機帶動盤片轉動來讀寫數(shù)據(jù)的看疙,而內存條通過電路來讀寫數(shù)據(jù),電機的轉速肯定沒有電的傳輸速度(幾乎是光速)快直奋。雖然固態(tài)硬盤也是通過電路來讀寫數(shù)據(jù)能庆,但是因為與內存的控制方式不一樣,速度也不及內存脚线。
所以搁胆,不管是運行QQ還是編輯Word文檔,都是先將硬盤上的數(shù)據(jù)復制到內存邮绿,才能讓CPU來處理渠旁,這個過程就叫作載入內存(Load into Memory)。完成這個過程需要一個特殊的程序(軟件)船逮,這個程序就叫做加載器(Loader)顾腊。
CPU直接與內存打交道,它會讀取內存中的數(shù)據(jù)進行處理挖胃,并將結果保存到內存杂靶。如果需要保存到硬盤梆惯,才會將內存中的數(shù)據(jù)復制到硬盤。
例如吗垮,打開Word文檔垛吗,輸入一些文字,雖然我們看到的不一樣了烁登,但是硬盤中的文檔沒有改變怯屉,新增的文字暫時保存到了內存,Ctrl+S才會保存到硬盤饵沧。因為內存斷電后會丟失數(shù)據(jù)锨络,所以如果你編輯完Word文檔忘記保存就關機了,那么你將永遠無法找回這些內容捷泞。
虛擬內存
如果我們運行的程序較多足删,占用的空間就會超過內存(內存條)容量。例如計算機的內存容量為2G锁右,卻運行著10個程序失受,這10個程序共占用3G的空間,也就意味著需要從硬盤復制 3G 的數(shù)據(jù)到內存咏瑟,這顯然是不可能的拂到。
操作系統(tǒng)(Operating System,簡稱 OS)為我們解決了這個問題:當程序運行需要的空間大于內存容量時码泞,會將內存中暫時不用的數(shù)據(jù)再寫回硬盤兄旬;需要這些數(shù)據(jù)時再從硬盤中讀取,并將另外一部分不用的數(shù)據(jù)寫入硬盤余寥。這樣领铐,硬盤中就會有一部分空間用來存放內存中暫時不用的數(shù)據(jù)。這一部分空間就叫做虛擬內存(Virtual Memory)宋舷。
3G - 2G = 1G绪撵,上面的情況需要在硬盤上分配 1G 的虛擬內存。
硬盤的讀寫速度比內存慢很多祝蝠,反復交換數(shù)據(jù)會消耗很多時間懦傍,所以如果你的內存太小堤结,會嚴重影響計算機的運行速度蚯涮,甚至會出現(xiàn)”卡死“現(xiàn)象侥涵,即使CPU強勁,也不會有大的改觀儡嘶。如果經(jīng)濟條件允許喇聊,建議將內存升級為 4G,在 win7蹦狂、win8 下運行軟件就會比較流暢了承疲。
總結:CPU直接從內存中讀取數(shù)據(jù)邻耕,處理完成后將結果再寫入內存。
圖1:CPU燕鸽、內存、硬盤和主板的關系
在C語言中啼辣,指針變量的值就是一個內存地址啊研,&運算符的作用也是取變量的內存地址,請看下面的代碼:
#include
#include
inta=1,b=255;
intmain(){
int*pa=&a;
printf("pa = %#X, &b = %#X\n",pa,&b);
system("pause");
return0;
}
在 C-Free 5.0 下運行鸥拧,結果為:
pa = 0X402000, &b = 0X402004
代碼中的 a党远、b 是全局變量,它們的內存地址在鏈接時就已經(jīng)決定了富弦,以后再也不能改變沟娱,該程序無論在何時運行,結果都是一樣的腕柜。
那么問題來了济似,如果物理內存中的這兩個地址被其他程序占用了怎么辦,我們的程序豈不是無法運行了盏缤?
幸運的是砰蠢,這些內存地址都是假的,不是真實的物理內存地址唉铜,而是虛擬地址台舱。虛擬地址通過CPU的轉換才能對應到物理地址,而且每次程序運行時潭流,操作系統(tǒng)都會重新安排虛擬地址和物理地址的對應關系竞惋,哪一段物理內存空閑就使用哪一段。如下圖所示:
虛擬地址的整個想法是這樣的:把程序給出的地址看做是一種虛擬地址(Virtual Address)灰嫉,然后通過某些映射的方法拆宛,將這個虛擬地址轉換成實際的物理地址。這樣熬甫,只要我們能夠妥善地控制這個虛擬地址到物理地址的映射過程胰挑,就可以保證程序每次運行時都可以使用相同的地址。
例如椿肩,上面代碼中變量 a 的地址是?0X402000瞻颂,第一次運行時它對應的物理內存地址可能是 0X12ED90AA,第二次運行時可能又對應 0XED90郑象,而我們的程序不需要關心這些贡这,這些繁雜的內存管理工作交給操作系統(tǒng)處理即可。
讓我們回到程序的運行本質上來厂榛。用戶程序在運行時不希望介入到這些復雜的內存管理過程中盖矫,作為普通的程序丽惭,它需要的是一個簡單的執(zhí)行環(huán)境,有自己的內存辈双,有自己的CPU责掏,好像整個程序占有整個計算機而不用關心其他的程序。
除了在編程時可以使用固定的內存地址湃望,給程序員帶來方便外换衬,使用虛擬地址還能夠使不同程序的地址空間相互隔離,提高內存使用效率证芭。
如果所有程序都直接使用物理內存瞳浦,那么程序所使用的地址空間不是相互隔離的。惡意程序可以很容易改寫其他程序的內存數(shù)據(jù)废士,以達到破壞的目的叫潦;有些非惡意、但是有 Bug 的程序也可能會不小心修改其他程序的數(shù)據(jù)官硝,導致其他程序崩潰矗蕊。
這對于需要安全穩(wěn)定的計算機環(huán)境的用戶來說是不能容忍的,用戶希望他在使用計算機的時候泛源,其中一個任務失敗了拔妥,至少不會影響其他任務。
使用了虛擬地址后达箍,程序A和程序B雖然都可以訪問同一個地址没龙,但它們對應的物理地址是不同的,無論如何操作缎玫,都不會修改對方的內存硬纤。
使用虛擬地址后,操作系統(tǒng)會更多地介入到內存管理工作中赃磨,這使得控制內存權限成為可能筝家。例如,我們希望保存數(shù)據(jù)的內存沒有執(zhí)行權限邻辉,保存代碼的內存沒有修改權限溪王,操作系統(tǒng)占用的內存普通程序沒有讀取權限等。
另外值骇,當物理內存不足時莹菱,操作系統(tǒng)能夠更加靈活地控制換入換出的粒度,磁盤 I/O 是非常耗時的工作吱瘩,這能夠從很大程度上提高程序性能道伟。
以上兩點我們將在《內存分頁機制》和《內存分頁機制的實現(xiàn)》中進行詳細講解。
在計算機中,為了讓操作更加直觀蜜徽、易于理解祝懂、增強用戶體驗,開發(fā)者經(jīng)常會使用一件法寶——增加中間層拘鞋,即使用一種間接的方式來屏蔽復雜的底層細節(jié)砚蓬,只給用戶提供簡單的接口。虛擬地址是使用中間層的一個典型例子掐禁。
實際上怜械,計算機的整個發(fā)展過程就是不斷引入新的中間層:
計算機的早期,程序都是直接運行在硬件之上傅事,自己負責硬件的管理工作;程序員也使用二進制進行編程峡扩,需要處理各種邊界條件和安全問題蹭越。
后來人們不能忍受了,于是開發(fā)出了操作系統(tǒng)教届,讓它來管理各種硬件响鹃,同時發(fā)明了匯編語言,減輕程序員的負擔案训。
隨著軟件規(guī)模的不斷增大买置,使用匯編語言編程開始變得捉襟見肘,不僅學習成本高强霎,開發(fā)效率也很低忿项,于是C語言誕生了。C語言編譯器先將C代碼翻譯為匯編代碼城舞,再由匯編器將匯編代碼翻譯成機器指令轩触。
隨著計算機的發(fā)展,硬件越來越強大家夺,軟件越來越復雜脱柱,人們又不滿足于使用C語言了,于是 C++拉馋、Java榨为、C#、PHP 等現(xiàn)代化的編程語言誕生了煌茴。
轉自C語言中文網(wǎng)高級部分