https://zhuanlan.zhihu.com/p/650723391
去年到現在一直在做的感測器資料管理框架中使用到了mmap實現多個程序間的資料共享,為了更快的實現感測器資料寫入到mmap中,同時便於檢視和除錯寫入的資料,我們沒有使用傳統的檔案來進行mmap對映,而是使用了/dev/shm目錄作為臨時檔案充當mmap的源,這樣將/dev/shm/a.dat檔案進行mmap對映,可以加快寫入速度和共享效率。原因就是/dev/shm雖然可以看做一個檔案目錄,但是它都是放在記憶體中的,重啟後會消失,所以作為臨時儲存,效率會非常高,並且裡面只儲存了最新的一幀資料,記憶體消耗量不大。最好用的是,你可以使用相關的軟體直接開啟它,檢視它的內容。
當時很早就想深入瞭解一下/dev/shm的啥原理,但是因為事情比較多給忘記了,前幾天看了個帖子發現介紹了/dev/shm,說的還不錯,就搬過來了。
一、/dev/shm理論
預設的Linux發行版中的核心配置都會開啟tmpfs,對映到了/dev/下的shm目錄。可以透過df 命令檢視結果.
/dev/shm/是linux下一個非常有用的目錄,因為這個目錄不在硬碟上,而是在記憶體裡。因此在linux下,就不需要大費周折去建ramdisk,直接使用/dev/shm/就可達到很好的最佳化效果。預設系統就會載入/dev/shm ,它就是所謂的tmpfs,有人說跟ramdisk(虛擬磁碟),但不一樣(後面給出區別)。象虛擬磁碟一樣,tmpfs 可以使用您的 RAM,但它也可以使用您的交換分割槽來儲存。而且傳統的虛擬磁碟是個塊裝置,並需要一個 mkfs 之類的命令才能真正地使用它,tmpfs 是一個檔案系統,而不是塊裝置;您只是安裝它,它就可以使用了。
tmpfs有以下優勢:
動態檔案系統的大小,/dev /shm/需要注意的一個是容量問題,在linux下,它預設最大為記憶體的一半大小,使用df -h命令可以看到。但它並不會真正的佔用這塊記憶體,如果/dev/shm/下沒有任何檔案,它佔用的記憶體實際上就是0位元組;如果它最大為1G,裡頭放有 100M檔案,那剩餘的900M仍然可為其它應用程式所使用,但它所佔用的100M記憶體,是絕不會被系統回收重新劃分的
tmpfs 的另一個主要的好處是它閃電般的速度。因為典型的 tmpfs 檔案系統會完全駐留在 RAM 中,讀寫幾乎可以是瞬間的。
tmpfs 資料在重新啟動之後不會保留,因為虛擬記憶體本質上就是易失的。所以有必要做一些指令碼做諸如載入,繫結的操作。
二、修改/dev/shm大小
預設的最大一半記憶體大小在某些場合可能不夠用,並且預設的inode數量很低一般都要調高些,這時可以用mount命令來管理它。
#mount -o size=1500M -o nr_inodes=1000000 -o noatime,nodiratime -o remount /dev/shm
在2G的機器上,將最大容量調到1.5G,並且inode數量調到1000000,這意味著大致可存入最多一百萬個小檔案。
如果需要永久修改/dev/shm的值,需要修改/etc/fstab
程式碼如下:
tmpfs /dev/shm tmpfs defaults,size=1.5G 0 0
mount -o remount /dev/shm
三、/dev/shm應用
首先在/dev/shm建個tmp資料夾,然後與實際/tmp繫結
程式碼如下:
#mkdir /dev/shm/tmp
#chmod 1777 /dev/shm/tmp
#mount –bind /dev/shm/tmp /tmp(–bind )
在使用mount –bind olderdir newerdir命令來掛載一個目錄到另一個目錄後,newerdir的許可權和所有者等所有資訊會發生變化。掛載後的目錄繼承了被掛載目錄的所有屬性,除了名稱。
三、tmpfs和ramfs的區別
ramfs和tmpfs是在記憶體上建立的檔案系統(Filesystem)。其優點是讀寫速度很快,但存在掉電丟失的風險。如果一個程序的效能瓶頸是硬碟的讀寫,那麼可以考慮在ramfs或tmpfs上進行大檔案的讀寫操作。
ramfs和tmpfs之間的區別:
ramfs和tmpfs的區別
特性 tmpfs ramfs
達到空間上限時繼續寫入 提示錯誤資訊並終止 可以繼續寫尚未分配的空間
是否固定大小 是 否
是否使用swap 是 否
具有易失性 是 是
檢視
透過下面的方法可以檢視系統中的tmpfs和ramfs:
ok@linux:~$ df -h | grep -E "(tmpfs|ramfs)"
devtmpfs 1.9G 16K 1.9G 1% /dev
tmpfs 1.9G 27M 1.9G 2% /dev/shm
tmpfs 1.9G 4.3M 1.9G 1% /run
tmpfs 1.9G 0 1.9G 0% /sys/fs/cgroup
tmpfs 1.9G 4.3M 1.9G 1% /var/lock
tmpfs 1.9G 4.3M 1.9G 1% /var/run
我的系統(Ubuntu 20.04,)中,使用的都是tmpfs。我想原因可能是,當存在寫溢位時,tmpfs比ramfs更加安全,因為前者會給出錯誤提示並禁止寫操作。
建立
建立tmpfs:
ok@linux:~ # mkdir -p /mnt/tmp
ok@linux:~ # mount -t tmpfs -o size=20m tmpfs /mnt/tmp/
ok@linux:~ # df -h | grep "/mnt/tmp"
tmpfs 20M 0 20M 0% /mnt/tmp
建立ramfs:
ok@linux:~ # mkdir -p /mnt/ram
ok@linux:~ # mount -t ramfs -o size=20m ramfs /mnt/ram/
ok@linux:~ # df -ah | grep "/mnt/ram"
ramfs 0 0 0 - /mnt/ram
這裡df只使用h選項是無法顯示ramfs的內容的。tmpfs會對記憶體進行accounting(統計記憶體的使用情況),而ramfs被設計為儘可能的簡單,所以不會進行accounting。因此,針對ramfs,在較新的核心中,使用df不會返回ramfs的資訊。
ramfs是Linux下一種基於RAM做儲存的檔案系統。在使用過程中你就可以把ramfs理解為在普通的HDD上建立了一個檔案系統,而現在HDD被替換成了RAM,因為是RAM做儲存所以會有很高的儲存效率。由於ramfs的實現就相當於把RAM作為最後一層的儲存,所以在ramfs中不會使用swap。你什麼時候聽過會把HDD上的檔案swap到哪裡去嗎?平常說的swap都是針對記憶體來說的,而ramfs底層的儲存是RAM,雖然不是HDD,但是在Linux看來它就跟HDD一樣。但是ramfs有一個很大的缺陷就是它會吃光系統所有的記憶體,即使你mount的時候指定了大小,同時它也只能被root使用者訪問。測試方法很簡單:
sudo mount -t ramfs -o size=10M ramfs ./ramfs/
sudo dd if=/dev/zero of=./ramfs/test.file bs=1M count=20
測試時你會發現上面這個操作是能成功的,或者你再自己虛擬機器上乾脆做狠點,直接寫一個比記憶體更大的檔案,你會發現瞬間系統就卡主了。另外在dd命令如果不以root使用者執行就會許可權不夠:
dd: opening `./ramfs/test.file': Permission denied
tmpfs也是Linux下的一個檔案系統,它將所有的檔案都儲存在虛擬記憶體中,umount tmpfs後所有的資料也會丟失,tmpfs就是ramfs的衍生品。tmpfs使用了虛擬記憶體的機制,它會進行swap,但是它有一個相比ramfs的好處:mount時指定的size引數是起作用的,這樣就能保證系統的安全,而不是像ramfs那樣,一不留心因為寫入資料太大吃光系統所有記憶體導致系統被hang住。在我文章最開始的那個例子中就是mount了一個10M大小的tmpfs,然後執行sql 命令(它需要建立的臨時表大於10M),因為tmpfs限制了大小,因此也就報錯。那麼tmpfs適用的場景有哪些呢?在官方文件上主要有如下幾點:
kernel 內部需要用到它,而我們是無法看到的
glibc 2.2以上的版本,必須有一個tmpfs被mount在/dev/shm用做POSIX shared memory
還有很多包括現在還不知道的用途
總結來說ramfs與tmpfs有如下幾點異同:
ramfs會因為資料的寫入自動增長空間,所以可能導致最後系統所有的記憶體耗完
tmpfs可以再mount時限定大小,不會自動增長
ramfs不會用swap
tmpfs會使用swap
兩者都是用來提升效率,但是tmpfs比ramfs的效能更好(結果是對的,原理有待進一步探究)