shm_open()
mmap()
預定義的大length
fork()
(多次)ftruncate()
隨意
這樣做的一點是要確保每一個通過fork()
衍生的進程有在同一地址共享段。然而,我不想讓內存一直很忙,只是動態調整它的大小(大小跨越0 - 大length
)。當mmap已經完成後共享內存對象是否安全?
可以工作嗎?有UB嗎?
shm_open()
mmap()
預定義的大length
fork()
(多次)ftruncate()
隨意這樣做的一點是要確保每一個通過fork()
衍生的進程有在同一地址共享段。然而,我不想讓內存一直很忙,只是動態調整它的大小(大小跨越0 - 大length
)。當mmap已經完成後共享內存對象是否安全?
可以工作嗎?有UB嗎?
不,這很好。您可以隨時截斷底層文件,但如果您訪問超出文件邊界的內存,則可能會收到SIGBUS
。所以,你需要非常小心,不要觸及超出當前文件長度的內存(或者趕上SIGBUS
並處理它)。
從man 2 mmap
:
使用映射的區域可導致這些信號:
SIGBUS
試圖訪問該不對應於 文件(例如,緩衝器的一部分,超越文件結尾,包括 其中另一個進程已截斷該文件的情況)。
不要調整它。
我不想保留RAM閒着
這就是內核會爲你做的虛擬內存。只要您不使用mlock()
或MAP_LOCKED
,它將根據需要/適當進行分頁。
嗯,RAM以及交換。我可能會在某些時候在映射區域的中間使用某些東西(迫使內核提交它),但是隨後我可能會在運行時的其餘部分中忘記它。所以我想我需要一種方法來明確地告訴我不再使用地址空間的那部分。 –
你可以使用'madvise()',但要注意行爲沒有保證。 –
我想我會使用'MADV_REMOVE'。但是如果我需要回這個空間,我該怎麼辦? –
創建儘可能大的映射,它不會「保持內存繁忙」,除非你真的使用它。
如果你擔心保持RAM忙你使用它做後,調用madvise(MADV_DONTNEED)
- 這將清除頁,還給你從零池中新的頁面,如果你再次訪問它們。
在寫入已標記爲「MADV_DONTNEED」的範圍之前,我不需要執行任何操作,對不對? –
請注意,只有在後備存儲不再具有這些頁面的情況下(因爲它可能存在某些數據可能已被'ftruncate'丟棄的問題),零填充行爲纔是。 –
@LorenzoPistone:你不需要做什麼,沒有。 'MADV_DONTNEED'將丟棄這些頁面,並且(如果由文件支持)根據需要從磁盤透明地重新加載頁面,或者(匿名映射)只會向您拋出零頁面。請注意,後者是 - 至少在我看來 - 實際上是「不正確的」行爲,因爲POSIX聲明語義不會被改變(這是相當的情況!)。不過,這正是你想要的。 – Damon
這就是我所假設的,但是'munmap'觸發器可以寫入可能觸發'SIGBUS'的髒頁嗎? –
標記爲已接受,因爲它回答了我的問題。但是Damon的方法更易於管理(我可以在'mmap'ed範圍中間卸載頁面)。 –
@nneonneo我不認爲這是正確的。我相信你需要在'ftruncate'之後執行'mremap'來更新映射。儘管如此,您仍應該先分配一個大尺寸來防止'mremap'與'ENOMEM'一起失敗。 – jleahy