Win 95下記憶體對映檔案的工作原理及使用方法 (轉)
Win 95下對映的工作原理及使用方法
一、引言
為我們提供了一種進行檔案操作的高效途徑,即記憶體對映檔案。記憶體對映檔案允許我們在WIN32程式的虛擬地址空間中保留一段記憶體區域,把目標檔案對映到這段虛擬記憶體之中。我們可以用存取記憶體資料的方式直接操作檔案中的資料,就好像這些資料放在記憶體中一樣。而實際上,我們並沒有、也不需要API來讀寫檔案,更不需要自己提供任何緩衝演算法,操作將會為我們完成這些工作。使用記憶體對映檔案能給開發工作提供極大的方便,程式的執行也非常高。
記憶體對映檔案在 NT和Windows95中的實現機制略有不同,下面主要介紹Windows95下記憶體對映檔案的工作原理及使用方法。
二、Windows95如何管理WIN32程式的記憶體空間
記憶體對映檔案的實現與Windows95的記憶體管理有密切的關係,因此先討論一下Windows95在執行WIN32程式時的記憶體管理與劃分。
在Windows3.x下,所有Windows應用程式共享單一的地址空間,任何程式都能夠對這一空間中屬於其他程式的記憶體進行讀寫操作,甚至可以存取本身的重要資料。在這種環境中,編寫不當的應用程式或者帶有惡意的應用程式,就可能破壞其他程式的資料或程式碼,使得系統執行不正常,嚴重時甚至會導致系統崩潰。
在實現了WIN32的作業系統和Windows95中,每個WIN32程式擁有自己的地址空間,一個WIN32程式不能存取另一個程式地址空間的私有資料,兩個程式可以用具有相同值的指標定址,但所讀寫的只是它們各自的資料,這樣就大大減少了程式之間的相互干擾,增強了系統的健壯性;另一方面,每個WIN32程式擁有4GB的地址空間,但並不代表它真正擁有4GB的實際實體記憶體,而只是作業系統利用的記憶體分頁功能提供的虛擬地址空間。在一般情況下,絕大多數虛擬地址並沒有實體記憶體與之對應,在真正可以使用這些地址空間之前,還要由作業系統提供實際的實體記憶體。為虛擬地址提供實際實體記憶體的過程叫做“提交”(Commit)。在不同情況下,系統提交的實體記憶體的型別是不同的,可能是RAM,也可能是模擬的虛擬記憶體。
Windows95對WIN32程式地址空間的劃分如下:
地址空間底部的4MB由Windows95用來維護與DOS和16位Windows的相容性。理想情況下,WIN32程式應該不能訪問這段記憶體,但由於實現上的困難,Windows95只能保護低端從0x00000000到0x00000FFF的4KB區域,這4KB區間用來捕獲NULL指標。從0x80000000到0xBFFFFFFF的1GB空間由所有的WIN32程式共享,記憶體對映檔案就使用這段地址空間。高階的1GB空間由Windows95自己使用,不像Windows NT那樣,這段空間也沒有受到保護,任何程式都可能破壞其中的資料。
三、記憶體對映檔案的工作原理
記憶體對映檔案分三種情況,第一種是可檔案的記憶體對映,主要由Windows95自身使用;第二種是資料檔案的記憶體對映;最後一種是藉助於頁面檔案的記憶體對映。應用程式可以使用後面兩種記憶體對映檔案。
1、可執行檔案的記憶體對映
Windows95在執行一個WIN32應用程式時使用記憶體對映檔案,它為將要執行的EXE檔案保留足夠大的地址空間。一般情況下,這段空間是從WIN32程式的載入地址0x00400000開始,系統給這段空間提交的物理就是硬碟上的EXE檔案本身。做好各項準備工作後,系統開始執行這個程式。剛開始,程式的程式碼並不在RAM中,執行程式入口的第一條指令時會產生一個頁面異常,系統捕獲到這個異常後,分配一塊RAM,將其對映到0x00400000處,並把實際程式碼讀入其中,然後繼續執行。以後在執行到不在RAM中的程式碼時,同樣會產生頁面異常,從而系統有機會讀入這些程式碼。系統以類似的方式處理WIN32DLL,只是DLL被對映到的地址空間是由所有WIN32程式共享的。
當執行同一個應用程式的第二個例項時,系統知道程式已經有一個例項了,EXE檔案的程式碼和資料已經被讀到RAM中,系統只需要把這段RAM再對映到新程式的地址空間就行了,這就實現了共享RAM中的程式碼和資料。事實上,這種共享只是針對只讀資料,一旦出現程式改寫自身程式碼和資料,作業系統會把被修改資料所在頁面複製一份,分配給執行寫操作的程式,從而避免了多個例項之間的相互干擾。
當然,作業系統執行一個WIN32應用程式的實際過程非常複雜,上面所描述的只是工作原理。我們可以用Softicefor Windows95來驗證作業系統是以對映檔案的方式來執行一個應用程式的:使用Wldr第一次調入一個應用程式如Notepad時,Softice被啟用。它所列出的程式的入口程式碼處全是Invalid(無效),這表明將要執行的程式碼所在頁面並不在RAM之中。按下F8,單步執行一條指令,螢幕上立刻列出了真正的程式指令,這是因為指令執行時首先產生了一個頁面異常,作業系統在處理頁面異常時,將程式碼讀入RAM之中。Softice再次被啟用時,就能看見剛讀入的指令了。進一步檢查還可以發現,系統每次只讀一個頁面(4KB)到RAM中,以便儘量節約記憶體。我們再用Wldr調入Notepad的第二個例項,這一次Softice被啟用後列出的入口程式碼不再是Invalid,而是真正的程式指令。由於Softice是系統級的器,用它修改記憶體中的應用程式時,作業系統並不做頁面複製。我們將Notepad的入口程式碼做一點改動,然後再用Wldr調入第三個例項。這次可以發現,列出的入口程式碼是剛剛修改過的,而實際的EXE檔案並無任何變化,這表明,作業系統把同一塊RAM中的程式程式碼對映到多個程式的地址空間中,從而實現了共享RAM中的程式程式碼。
2、資料檔案的記憶體對映
資料檔案記憶體對映的工作原理與可執行檔案的記憶體對映原理是一樣的。首先把資料檔案的一部分對映到虛擬地址空間(對映到的區域是在0x80000000-0xBFFFFFFF內),但不提交RAM,存取這段記憶體的指令同樣會產生頁面異常。作業系統捕獲到這個異常後,分配一頁RAM,並把它對映到當前程式發生異常的地址處,然後系統把檔案中相應的資料讀到這個頁面中,繼續執行剛才產生異常的指令。這就是應用程式自己不需要呼叫檔案I/O函式的原因。
3、基於頁面交換檔案的記憶體對映
記憶體對映檔案的第三種情況是基於頁面交換檔案的。一個WIN32程式可以利用記憶體對映檔案在WIN32程式共享的地址空間中保留一塊區域,這塊區域與系統的頁面交換檔案相聯絡。我們可以用它來儲存臨時資料,但更常見的用法是,利用它與其他WIN32程式進行通訊。事實上,WIN32實現多程式間通訊的各種方法都是透過記憶體對映檔案來實現的,例如PostMessage()函式或SendMessage()函式,在內部都使用了記憶體對映檔案。
四、使用記憶體對映檔案的方法
1、利用記憶體對映檔案進行檔案I/O操作,進行檔案I/O操作需要下面幾個步驟:
步驟一:呼叫CreateFile()函式,以適當的方式建立或開啟一個檔案核心;
步驟二:把CreateFile()函式返回的檔案控制程式碼作為引數,傳給CreateFileMap()函式,由CreateFileMapping()函式建立一個檔案對映核心物件的適當屬性;
步驟三:建立了檔案對映核心物件後,呼叫MapViewOfFile()函式,告訴系統把檔案的哪一部分對映到程式的地址空間中,以何種方式對映;
步驟四:利用MapViewOfFile()函式返回的指標來使用檔案資料;
步驟五:操作完畢後,呼叫UnmapViewOfFile()函式,告訴系統撤銷對檔案對映核心物件的對映;
步驟六:使用CloseHandle()函式關閉檔案對映核心物件;
步驟七:使用CloseHandle()函式關閉檔案核心物件;
各個API函式的詳細說明請參考Windows95SDK或一些工具的聯機幫助。
2、利用記憶體對映檔案實現WIN32程式間的通訊
在Windows95下,一個程式開啟的檔案對映物件的對映區對所有的WIN32程式都是可視的,並且對映區的地址對所有WIN32程式都是一樣的。一個程式可以開啟一個檔案,建立檔案對映核心物件,用MapViewOfFile()函式開啟檔案檢視,然後將檔案對映的地址傳給另一個程式,第二個程式就可以讀出檔案中的資料。這種方法需要進行各程式間的同步,實現起來較困難。並且在Windows NT中,一個對映區在不同的WIN32程式空間中對應的地址不同,因此為了與Windows NT相容,儘量不要使用這種方法。
第二種方法是兩個程式使用同一檔案對映核心物件,開啟各自的檢視,或者父程式把自己建立的檔案對映核心物件繼承給子程式使用。這種方法比較有效。
第三種方法是建立基於頁面交換檔案的記憶體對映物件。在呼叫CreateFileMapping()函式時,傳遞檔案控制程式碼為0xFFFFFFFF,系統就從頁面交換檔案中提交物理儲存,然後程式之間按照第二種方法進行通訊。這種方法不用事先準備一個特殊的檔案,非常方便。(廣西 王有明)
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-988834/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- VC++中用記憶體對映檔案 (轉)C++記憶體
- 使用記憶體對映檔案(mmap)記憶體
- 一個記憶體檔案對映使用者類 (轉)記憶體
- Python mmap的使用-檔案記憶體對映Python記憶體
- 二進位制檔案記憶體對映記憶體
- 記憶體對映檔案詳解-----C++實現(即一塊記憶體和一個檔案相對映對應)記憶體C++
- windows核心程式設計--記憶體對映檔案Windows程式設計記憶體
- 居然這就是C++記憶體對映檔案?!C++記憶體
- 記憶體對映記憶體
- 非同步日誌 vs. 記憶體對映檔案非同步記憶體
- Java使用記憶體對映實現大檔案的上傳Java記憶體
- mmap記憶體對映記憶體
- Linux 記憶體管理:記憶體對映Linux記憶體
- Java記憶體的原型及工作原理深度剖析Java記憶體原型
- Java記憶體對映,上G大檔案輕鬆處理Java記憶體
- 溫故之.NET程式間通訊——記憶體對映檔案記憶體
- C# .Net 多程式同步 通訊 共享記憶體 記憶體對映檔案 Memory MappedC#記憶體APP
- JAVA記憶體對映檔案實現多執行緒下載Java記憶體執行緒
- C#記憶體對映大檔案並使用Marshal解析結構體資訊C#記憶體結構體
- Java 中使用記憶體對映檔案需要考慮的 10 個問題Java記憶體
- 【IPC程式間通訊之三】記憶體對映檔案Mapping FileC程式記憶體APP
- 虛擬記憶體系統——瞭解記憶體的工作原理記憶體
- 從核心世界透視 mmap 記憶體對映的本質(原理篇)記憶體
- 從記憶體對映mmap說開去記憶體
- 虛擬記憶體,實體記憶體,頁面檔案,還有工作管理員記憶體
- linux記憶體管理(八)- 反向對映RMAPLinux記憶體
- Java記憶體管理原理及記憶體區域詳解Java記憶體
- 一個故事看懂記憶體條工作原理記憶體
- 【譯】JavaScript的工作原理:記憶體管理和4種常見的記憶體洩漏JavaScript記憶體
- JavaScript 工作原理之三-記憶體管理及如何處理 4 類常見的記憶體洩漏問題(譯)JavaScript記憶體
- [譯] JavaScript 工作原理:記憶體管理 + 處理常見的4種記憶體洩漏JavaScript記憶體
- IP對映原理及怎樣把內網IP對映外網內網
- Mybatis的Mapper對映檔案中常用標籤及作用MyBatisAPP
- win10電腦記憶體測試軟體怎麼用_win10記憶體檢測工具的使用方法Win10記憶體
- hibernate筆記–實體類對映檔案”*.hbm.xml”詳解筆記XML
- Java 8 記憶體管理原理解析及記憶體故障排查實踐Java記憶體
- Java記憶體問題 及 LeakCanary 原理分析Java記憶體
- Mybatis對映檔案簡介MyBatis