2013-01-15 42 views
3

我有一個場景,我需要在進程空間中線性映射文件的非線性部分。linux - 映射文件的非線性部分

例如, 如果文件是10頁,則可能需要映射前3個,跳過4個和最後3個。 映射應該是線性的,s.t.進程空間中的增量訪問允許在第3頁之後進入文件的第8頁,因爲未映射頁面4,5,6 & 7。

我想知道這是否可能在Linux中。

謝謝。

+0

這不僅僅是多次調用'mmap'的情況嗎? –

+0

多次不會調用mmap爲每個mmap調用提供指針結果?我有整個映射只需要一個指針結果的場景。它不可行嗎? – Jake

+0

我已經用'mmap'完成了一段時間,但它不是可選地址的參數之一? –

回答

4

多次使用MAP_FIXED爲第二個映射和後續映射指定固定地址的策略應該可行,但問題是如果在第一個映射之後已經有任何內容已經映射到內存中,它將會得到因爲MAP_FIXED在做出新的映射之前自動取消映射曾經存在的內容。

我看了一下Linux系統地址空間的一些映射的佈局,我發現至少在某些時候,內核爲內存映射選擇的地址從高到低地址到低地址。也就是說,一個新的映射被賦予緊靠最近現有映射所使用的地址空間之下的地址空間。在這種策略下,當你進行第一次映射時,幾乎可以保證映射後面的地址空間已經被其他東西佔據了(它也可能是重要的,就像系統庫一樣)。其他系統(不同的內核版本,不同的體系結構或非Linux等)可能會使用不同的地址空間分配策略,這些策略不會使這個問題不太可能發生,但是您應該認爲它可以發生並通過使用以下技術。

  1. 首先製作一個虛擬映射,它是要構建的所有映射大小的總和。因此,如果您想要映射文件的前3個頁面,則跳過4,然後映射另外3個頁面,製作6個頁面的虛擬映射。

    對於此虛擬映射,您可以映射匿名內存(MAP_ANONYMOUS)。感謝Basile Starynkevitch的建議,也使用MAP_NORESERVE進行此映射。

  2. 與你真正想要的文件映射塊替換此虛擬映射片,採用MAP_FIXED指定您希望每個映射出現在精確的地址。

    編輯:我本來建議重用爲新映射的地址空間之前,摧毀與munmap()虛擬映射,但由於jstine的指出,這是不必要的(它引入了競爭條件,如果你的程序是多線程) 。

    對於第一次映射,通過虛擬映射使用起始地址。計算第二個映射的地址作爲虛擬映射的起始地址加上第一個映射的大小。這應該在第一次映射結束後立即放置第二次映射。對於第三和第四映射等等。在你的場景中,所有內容都是頁面大小和頁面對齊的,所以不會因爲對齊而出現間隙。

完成第2步中的所有映射後,原始虛擬映射應該沒有剩下任何內容。

+0

如果你的控制之外的另一個程序在你銷燬虛擬映射並意外地選擇了這個很好的免費「洞」之後使用mmap,會發生什麼?我不相信這可以可靠地工作 – sl0815

+0

@ sl0815:你正在映射到虛擬內存,你不是嗎?所以其他程序不會影響你。 (但是,我對此策略是否可靠工作沒有評論......) –

+0

我應該仔細閱讀這些手冊頁。 @everyone:忽略我上面的愚蠢評論。 – sl0815

4

除了Celada的previous answer以外,您可能還會對您的mmap(2)之後的Linux特定remap_file_pages(2)系統調用感興趣。

而第一個mmap可能會使用MAP_NORESERVE來避免花費交換空間(只保留地址空間,而不是數據)。

+0

感謝您提供這些額外的建議。我不知道「remap_file_pages()」和「MAP_NORESERVE」。非常特定的Linux和非可移植的,我期望:-) – Celada

+0

AFAIR,'MAP_NORESERVE'可用於其他一些系統(也許是Solaris)。但'remap_file_pages'確實非常適合Linux。 –