1. 共享內存 linux下怎麼跑
linux 共享內存實現
說起共享內存,一般來說會讓人想起下面一些方法:
1、多線程。線程之間的內存都是共享的。更確切的說,屬於同一進程的線程使用的是同一個地址空間,而不是在不同地址空間之間進行內存共享;
2、父子進程間的內存共享。父進程以MAP_SHARED|MAP_ANONYMOUS選項mmap一塊匿名內存,fork之後,其子孫進程之間就能共享這塊內存。這種共享內存由於受到進程父子關系的限制,一般較少使用;
3、mmap文件。多個進程mmap到同一個文件,實際上就是大家在共享文件pagecache中的內存。不過文件牽涉到磁碟的讀寫,用來做共享內存顯然十分笨重,所以就有了不跟磁碟扯上關系的內存文件,也就是我們這里要討論的tmpfs和shmem;
tmpfs是一套虛擬的文件系統,在其中創建的文件都是基於內存的,機器重啟即消失。
shmem是一套ipc,通過相應的ipc系統調用shmget能夠以指定key創建一塊的共享內存。需要使用這塊內存的進程可以通過shmat系統調用來獲得它。
雖然是兩套不同的介面,但是在內核裡面的實現卻是同一套。shmem內部掛載了一個tmpfs分區(用戶不可見),shmget就是在該分區下獲取名為"SYSV${key}"的文件。然後shmat就相當於mmap這個文件。
所以我們接下來就把tmpfs和shmem當作同一個東西來討論了。
tmpfs/shmem是一個介於文件和匿名內存之間的東西。
一方面,它具有文件的屬性,能夠像操作文件一樣去操作它。它有自己inode、有自己的pagecache;
另一方面,它也有匿名內存的屬性。由於沒有像磁碟這樣的外部存儲介質,內核在內存緊缺時不能簡單的將page從它們的pagecache中丟棄,而需要swap-out;(參閱《linux頁面回收淺析》)
對tmpfs/shmem內存的讀寫,就是對pagecache中相應位置的page所代表的內存進行讀寫,這一點跟普通的文件映射沒有什麼不同。
如果進程地址空間的相應位置尚未映射,則會建立到pagecache中相應page的映射;
如果pagecache中的相應位置還沒有分配page,則會分配一個。當然,由於不存在磁碟上的源數據,新分配的page總是空的(特別的,通過read系統調用去讀一個尚未分配page的位置時,並不會分配新的page,而是共享ZERO_PAGE);
如果pagecache中相應位置的page被回收了,則會先將其恢復;
對於第三個「如果」,tmpfs/shmem和普通文件的page回收及其恢復方式是不同的:
page回收時,跟普通文件的情況一樣,內核會通過prio_tree反向映射找到映射這個page的每一個pagetable,然後將其中對應的pte清空。
不同之處是普通文件的page在確保與磁碟同步(如果page為臟的話需要刷回磁碟)之後就可以丟棄了,而對於tmpfs/shmem的page則需要進行swap-out。
注意,匿名page在被swap-out時,並不是將映射它的pte清空,而是得在pte上填寫相應的swap_entry,以便知道page被換出到哪裡去,否則再需要這個page的時候就沒法swap-in了。
而tmpfs/shmem的page呢?pagetable中對應的pte被清空,swap_entry會被存放在pagecache的radix_tree的對應slot上。
等下一次訪問觸發pagefault時,page需要恢復。
普通文件的page恢復跟page未分配時的情形一樣,需要新分配page、然後根據映射的位置重新從磁碟讀出相應的數據;
而tmpfs/shmem則是通過映射的位置找到radix_tree上對應的slot,從中得到swap_entry,從而進行swap-in,並將新的page放回pagecache;
這里就有個問題了,在pagecache的radix_tree的某個slot上,怎麼知道裡面存放著的是正常的page?還是swap-out後留下的swap_entry?
如果是swap_entry,那麼slot上的值將被加上RADIX_TREE_EXCEPTIONAL_ENTRY標記(值為2)。swap_entry的值被左移兩位後OR上RADIX_TREE_EXCEPTIONAL_ENTRY,填入slot。
也就是說,如果${slot}&RADIX_TREE_EXCEPTIONAL_ENTRY!=0,則它代表swap_entry,且swap_entry的值是${slot}>>2;否則它代表page,${slot}就是指向page的指針,當然其值可能是NULL,說明page尚未分配。
那麼顯然,page的地址值其末兩位肯定是0,否則就可能跟RADIX_TREE_EXCEPTIONAL_ENTRY標記沖突了;而swap_entry的值最大隻能是30bit或62bit(對應32位或64位機器),否則左移兩位就溢出了。
最後以一張圖說明一下匿名page、文件映射page、tmpfs/shmempage的回收及恢復過程:
2. 在linux中共享內存里分別存放了整數和字元,怎麼將它們分別取出來
一、應用
共享內存的使用,主要有以下幾個API:ftok()、shmget()、shmat()、shmdt()及shmctl()。
1)用ftok()函數獲得一個ID號.
應用說明:
在IPC中,我們經常用用key_t的值來創建或者打開信號量,共享內存和消息隊列。
函數原型:
key_t ftok(const char *pathname, int proj_id);
Keys:
1)pathname一定要在系統中存在並且進程能夠訪問的
3)proj_id是一個1-255之間的一個整數值,典型的值是一個ASCII值。
當成功執行的時候,一個key_t值將會被返回,否則-1被返回。我們可以使用strerror(errno)來確定具體的錯誤信息。
考慮到應用系統可能在不同的主機上應用,可以直接定義一個key,而不用ftok獲得:
#define IPCKEY 0x344378
2)shmget()用來開辟/指向一塊共享內存的函數
應用說明:
shmget()用來獲得共享內存區域的ID,如果不存在指定的共享區域就創建相應的區域。
函數原型:
int shmget(key_t key, size_t size, int shmflg);
key_t key 是這塊共享內存的標識符。如果是父子關系的進程間通信的話,這個標識符用IPC_PRIVATE來代替。如果兩個進程沒有任何關系,所以就用ftok()算出來一個標識符(或者自己定義一個)使用了。
int size 是這塊內存的大小.
int flag 是這塊內存的模式(mode)以及許可權標識。
模式可取如下值:
IPC_CREAT 新建(如果已創建則返回目前共享內存的id)
IPC_EXCL 與IPC_CREAT結合使用,如果已創建則則返回錯誤
然後將「模式」 和「許可權標識」進行「或」運算,做為第三個參數。
如: IPC_CREAT | IPC_EXCL | 0640
例子中的0666為許可權標識,4/2/1 分別表示讀/寫/執行3種許可權,第一個0是UID,第一個6(4+2)表示擁有者的許可權,第二個4表示同組許可權,第3個0表示他人的許可權。
這個函數成功時返回共享內存的ID,失敗時返回-1。
關於這個函數,要多說兩句。
創建共享內存時,shmflg參數至少需要 IPC_CREAT | 許可權標識,如果只有IPC_CREAT 則申請的地址都是k=0xffffffff,不能使用;
獲取已創建的共享內存時,shmflg不要用IPC_CREAT(只能用創建共享內存時的許可權標識,如0640),否則在某些情況下,比如用ipcrm刪除共享內存後,用該函數並用IPC_CREAT參數獲取一次共享內存(當然,獲取失敗),則即使再次創建共享內存也不能成功,此時必須更改key來重建共享內存。
3. 一般來說,在linux中使用共享內存的流程應該怎樣
可以使用samba協議。Samba是在Linux和UNIX系統上實現SMB協議的一個免費軟體,由伺服器及客戶端程序構成。SMB是一種在區域網上共享文件和列印機的一種通信協議,它為區域網內的不同計算機之間提供文件及列印機等資源的共享服務。具體配置步驟如下:
步驟1:安裝samba
sudo apt-get install samba samba-common-bin
步驟2:新建共享目錄並設置許可權
sudo mkdir /home/share
sudo chmod 777 /home/share
步驟3:修改配置文件
sudo nano /etc/samba/smb.conf
在smb.conf最後添加:
[share]
path = /home/share
browseable = yes
writable = yes
comment = smb share test
public = no#yes無需密碼 no需要密碼
步驟4:添加遠程訪問用戶
sudo useradd smbuser
sudo smbpasswd -a smbuser
步驟5:重新啟動服務
sudo service samba restart
對於windows操作系統,在資源管理器里輸入\\Linux的IP地址,會提示輸入上述步驟設置的用戶名和密碼,輸入正確後即可訪問分享內容。
4. linux共享內存的分配
進程通過調用shmget(Shared Memory GET,獲取共享內存)來分配一個共享內存塊。
該函數的第一個參數是一個用來標識共享內存塊的鍵值。彼此無關的進程可以通過指定同一個鍵以獲取對同一個共享內存塊的訪問。不幸的是,其它程序也可能挑選了同樣的特定值作為自己分配共享內存的鍵值,從而產生沖突。用特殊常量IPC_PRIVATE作為鍵值可以保證系統建立一個全新的共享內存塊。
該函數的第二個參數指定了所申請的內存塊的大小。因為這些內存塊是以頁面為單位進行分配的,實際分配的內存塊大小將被擴大到頁面大小的整數倍。
第三個參數是一組標志,通過特定常量的按位或操作來shmget。這些特定常量包括:
IPC_CREAT:這個標志表示應創建一個新的共享內存塊。通過指定這個標志,我們可以創建一個具有指定鍵值的新共享內存塊。
IPC_EXCL:這個標志只能與 IPC_CREAT 同時使用。當指定這個標志的時候,如果已有一個具有這個鍵值的共享內存塊存在,則shmget會調用失敗。也就是說,這個標志將使線程獲得一個「獨有」的共享內存塊。如果沒有指定這個標志而系統中存在一個具有相同鍵值的共享內存塊,shmget會返回這個已經建立的共享內存塊,而不是重新創建一個。
模式標志:這個值由9個位組成,分別表示屬主、屬組和其它用戶對該內存塊的訪問許可權。其中表示執行許可權的位將被忽略。指明訪問許可權的一個簡單辦法是利用<sys/stat.h>中指定,並且在手冊頁第二節stat條目中說明了的常量指定。例如,S_IRUSR和S_IWUSR分別指定了該內存塊屬主的讀寫許可權,而 S_IROTH和S_IWOTH則指定了其它用戶的讀寫許可權。 下面例子中shmget函數創建了一個新的共享內存塊(當shm_key已被佔用時則獲取對一個已經存在共享內存塊的訪問),且只有屬主對該內存塊具有讀寫許可權,其它用戶不可讀寫。
int segment_id = shmget (shm_key, getpagesize (), IPC_CREAT | S_IRUSR| S_IWUSR ); 如果調用成功,shmget將返回一個共享內存標識符。如果該共享內存塊已經存在,系統會檢查訪問許可權,同時會檢查該內存塊是否被標記為等待摧毀狀態。
5. 如何設置linux的共享內存
首先先使用shmget建立一塊共享內存,然後向該內存中寫入數據並返回該共享內存shmid
使用另一個程序通過上一程序返回的shmid讀該共享內存內的數據
建立共享內存並寫入數據的程序
#include<stdio.h>
#include<string.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<stdlib.h>
#include<errno.h>
voidget_buf(char*buf)
{
inti=0;
while((buf[i]=getchar())!=' '&&i<1024)
i++;
}
intmain(void)
{
intshmid;
shmid=shmget(IPC_PRIVATE,sizeof(char)*1024,IPC_CREAT|0666);
if(shmid==-1)
{
perror("shmget");
}
char*buf;
if((int)(buf=shmat(shmid,NULL,0))==-1)
{
perror("shmat");
exit(1);
}
get_buf(buf);
printf("%d ",shmid);
return0;
}
讀取數據的程序
#include<stdio.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<stdlib.h>
intmain(intargc,char**argv)
{
intshmid;
shmid=atoi(argv[1]);
char*buf;
if((int)(buf=shmat(shmid,NULL,0))==-1)
{
perror("shmat");
exit(1);
}
printf("%s ",buf);
shmdt(buf);
return0;
}
命令行的第一個參數設為第一個程序輸出的數字
如
使用完以後可以使用
ipcrm -m 19562507
來刪除該共享內存
6. 共享內存原理
Linux的2.2.x內核支持多種共享內存方式,如mmap()系統調用,Posix共享內存,以及系統V共享內存。
共享內存可以說是最有用的進程間通信方式,也是最快的IPC形式。兩個不同進程A、B共享內存的意思是,同一塊物理內存被映射到進程A、B各自的進程地址空間。進程A可以即時看到進程B對共享內存中數據的更新,反之亦然。由於多個進程共享同一塊內存區域,必然需要某種同步機制,互斥鎖和信號量都可以。
系統V共享內存原理
進程間需要共享的數據被放在一個叫做IPC共享內存區域的地方,所有需要訪問該共享區域的進程都要把該共享區域映射到本進程的地址空間中去。系統V共享內存通過shmget獲得或創建一個IPC共享內存區域,並返回相應的標識符。內核在保證shmget獲得或創建一個共享內存區,初始化該共享內存區相應的shmid_kernel結構注同時,還將在特殊文件系統shm中,創建並打開一個同名文件,並在內存中建立起該文件的相應dentry及inode結構,新打開的文件不屬於任何一個進程(任何進程都可以訪問該共享內存區)。所有這一切都是系統調用shmget完成的。
Linux 有一個系統調用叫 mmap(),這個 mmap() 可以把一個文件映射到進程的地址空間(進程使用的虛擬內存),這樣進程就可以通過讀寫這個進程地址空間來讀寫這個文件。
你可能會覺得奇怪,我明明寫的是內存啊,怎麼會變成寫文件了呢?他們之間是怎麼轉化的呢?
沒錯,你寫的確實是內存,但是你寫的這個內存不是普通的內存,你寫在這個內存上的內容,過段時間後會被內核寫到這個文件上面。而寫文件,其實最後都會變成寫數據到設備里(硬碟、Nand Flash 等)。
mmap的優點主要在為用戶程序隨機的訪問,操作,文件提供了一個方便的操作方法;其次就是為不同進程共享大批量數據提供高效的手段;另外就是對特大文件(無法一次性讀入內存)的處理提供了一種有效的方法。
內核里存在著一個特殊的文件系統,這個文件系統的存儲介質不是別的,正是 RAM。
在 shmget() 調用之後,系統會為你在這個文件系統上創建一個文件,但是這個時候僅僅是創建了這個文件。
然後你就應該調用 shmat() 了,調用 shmat() 之後,內核會使用 mmap 把這個文件映射到你的進程地址空間,這個時候你就能直接讀寫映射後的地址了。
過段時間,內核把你寫的 內容寫到了文件裡面,但是,這個文件的存儲介質是內存,所以他會怎麼做?看明白了吧?
答案:他會寫入內存呀
我們先來看看如果不使用內存映射文件的處理流程是怎樣的,首先我們得先讀出磁碟文件的內容到內存中,然後修改,最後回寫到磁碟上。第一步讀磁碟文件是要經過一次系統調用的,它首先將文件內容從磁碟拷貝到內核空間的一個緩沖區,然後再將這些數據拷貝到用戶空間,實際上是兩次數據拷貝。第三步回寫也一樣也要經過兩次數據拷貝。
所以我們基本上會有四次數據的拷貝了,因為大文件數據量很大,幾十GB甚至更大,所以拷貝的開銷是非常大的。
而內存映射文件是操作系統的提供的一種機制,可以減少這種不必要的數據拷貝,從而提高效率。它由mmap()將文件直接映射到用戶空間,mmap()並沒有進行數據拷貝,真正的數據拷貝是在缺頁中斷處理時進行的,由於mmap()將文件直接映射到用戶空間,所以中斷處理函數根據這個映射關系,直接將文件從硬碟拷貝到用戶空間,所以只進行了一次數據拷貝 ,比read進行兩次數據拷貝要好上一倍,因此,內存映射的效率要比read/write效率高。
一般來說,read write操作可以滿足大多數文件操作的要求,但是對於某些特殊應用領域所需要的幾十GB甚至更大的存儲,這種通常的文件處理方法進行處理顯然是行不通的。
mmap將一個文件或者其它對象映射進內存。文件被映射到多個頁上,如果文件的大小不是所有頁的大小之和,最後一個頁不被使用的空間將會清零。munmap執行相反的操作,刪除特定地址區域的對象映射。
當使用mmap映射文件到進程後,就可以直接操作這段虛擬地址進行文件的讀寫等操作,不必再調用read,write等系統調用.但需注意,直接對該段內存寫時不會寫入超過當前文件大小的內容.
參考地址:
7. LINUX系統的內存管理知識詳解
內存是Linux內核所管理的最重要的資源之一。內存管理系統是操作系統中最為重要的部分,因為系統的物理內存總是少於系統所需要的內存數量。虛擬內存就是為了克服這個矛盾而採用的策略。系統的虛擬內存通過在各個進程之間共享內存而使系統看起來有多於實際內存的內存容量。Linux支持虛擬內存, 就是使用磁碟作為RAM的擴展,使可用內存相應地有效擴大。核心把當前不用的內存塊存到硬碟,騰出內存給其他目的。當原來的內容又要使用時,再讀回內存。以下就是我為大家整理到的詳細LINUX系統內存管理的知識,歡迎大家閱讀!!!
LINUX系統教程:內存管理的知識詳解
一、內存使用情況監測
(1)實時監控內存使用情況
在命令行使用「Free」命令可以監控內存使用情況
代碼如下:
#free
total used free shared buffers cached
Mem: 256024 192284 63740 0 10676 101004
-/+ buffers/cache: 80604 175420
Swap: 522072 0 522072
上面給出了一個256兆的RAM和512兆交換空間的系統情況。第三行輸出(Mem:)顯示物理內存。total列不顯示核心使用的物理內存(通常大約1MB)。used列顯示被使用的內存總額(第二行不計緩沖)。 free列顯示全部沒使用的內存。Shared列顯示多個進程共享的內存總額。Buffers列顯示磁碟緩存的當前大小。第五行(Swap:)對對換空間,顯示的信息類似上面。如果這行為全0,那麼沒使用對換空間。在預設的狀態下,free命令以千位元組(也就是1024位元組為單位)來顯示內存使用情況。可以使用—h參數以位元組為單位顯示內存使用情況,或者可以使用—m參數以兆位元組為單位顯示內存使用情況。還可以通過—s參數使用命令來不間斷地監視內存使用情況:
#free –b –s2
這個命令將會在終端窗口中連續不斷地報告內存的使用情況,每2秒鍾更新一次。
(2)組合watch與 free命令用來實時監控內存使用情況:
代碼如下:
#watch -n 2 -d free
Every 2.0s: free Fri Jul 6 06:06:12 2007
total used free shared buffers cached
Mem: 233356 218616 14740 0 5560 64784
-/+ buffers/cache: 148272 85084
Swap: 622584 6656 615928
watch命令會每兩秒執行 free一次,執行前會清除屏幕,在同樣位置顯示數據。因為 watch命令不會卷動屏幕,所以適合出長時間的監測內存使用率。可以使用 -n選項,控制執行的頻率;也可以利用 -d選項,讓命令將每次不同的地方顯示出來。Watch命令會一直執行,直到您按下 [Ctrl]-[C] 為止。
二、虛擬內存的概念
(1)Linux虛擬內存實現機制
Linux虛擬內存的實現需要六種機制的支持:地址映射機制、內存分配回收機制、緩存和刷新機制、請求頁機制、交換機制、內存共享機制。
首先內存管理程序通過映射機制把用戶程序的邏輯地址映射到物理地址,在用戶程序運行時如果發現程序中要用的虛地址沒有對應的物理內存時,就發出了請求頁要求;如果有空閑的內存可供分配,就請求分配內存(於是用到了內存的分配和回收),並把正在使用的物理頁記錄在緩存中(使用了緩存機制)。 如果沒有足夠的內存可供分配,那麼就調用交換機制,騰出一部分內存。另外在地址映射中要通過TLB(翻譯後援存儲器)來尋找物理頁;交換機制中也要用到交換緩存,並且把物理頁內容交換到交換文件中後也要修改頁表來映射文件地址。
(2)虛擬內存容量設定
也許有人告訴你,應該分配2倍於物理內存的虛擬內存,但這是個不固定的規律。如果你的物理保存比較小,可以這樣設定。如果你有1G物理內存或更多的話,可以縮小一下虛擬內存。Linux會把大量的內存用做Cache的,但在資源緊張時回收回.。你只要看到swap為0或者很小就可以放心了,因為內存放著不用才是最大的浪費。
三、使甩vmstat命令監視虛擬內存使用情況
vmstat是Virtual Meomory Statistics(虛擬內存統計)的縮寫,可對操作系統的虛擬內存、進程、CPU活動進行監視。它是對系統的整體情況進行統計,不足之處是無法對某個進程進行深入分析。通常使用vmstat 5 5(表示在5秒時間內進行5次采樣)命令測試。將得到一個數據匯總它可以反映真正的系統情況。
代碼如下:
#vmstat 5 5
procs -----------memory---------- ---swap-- -----io---- --system-- ----cpu----
r b swpd free buff cache si so bi bo in cs us sy id wa
1 0 62792 3460 9116 88092 6 30 189 89 1061 569 17 28 54 2
0 0 62792 3400 9124 88092 0 0 0 14 884 434 4 14 81 0
0 0 62792 3400 9132 88092 0 0 0 14 877 424 4 15 81 0
1 0 62792 3400 9140 88092 0 0 0 14 868 418 6 20 74 0
1 0 62792 3400 9148 88092 0 0 0 15 847 400 9 25 67 0
vmstat命令輸出分成六個部分:
(1)進程procs:
r:在運行隊列中等待的進程數 。
b:在等待io的進程數 。
(2)內存memoy:
swpd:現時可用的交換內存(單位KB)。
free:空閑的內存(單位KB)。
buff: 緩沖去中的內存數(單位:KB)。
cache:被用來做為高速緩存的內存數(單位:KB)。
(3) swap交換頁面
si: 從磁碟交換到內存的交換頁數量,單位:KB/秒。
so: 從內存交換到磁碟的交換頁數量,單位:KB/秒。
(4) io塊設備:
bi: 發送到塊設備的塊數,單位:塊/秒。
bo: 從塊設備接收到的塊數,單位:塊/秒。
(5)system系統:
in: 每秒的中斷數,包括時鍾中斷。
cs: 每秒的環境(上下文)切換次數。
(6)cpu中央處理器:
cs:用戶進程使用的時間 。以百分比表示。
sy:系統進程使用的時間。 以百分比表示。
id:中央處理器的空閑時間 。以百分比表示。
如果 r經常大於 4 ,且id經常小於40,表示中央處理器的負荷很重。 如果bi,bo 長期不等於0,表示物理內存容量太小。
四、Linux 伺服器的內存泄露和回收內存的方法
1、內存泄漏的定義:
一般我們常說的內存泄漏是指堆內存的泄漏。堆內存是指程序從堆中分配的,大小任意的(內存塊的大小可以在程序運行期決定),使用完後必須顯示釋放的內存。應用程序一般使用malloc,realloc,new等函數從堆中分配到一塊內存,使用完後,程序必須負責相應的調用free或釋放該內存塊,否則,這塊內存就不能被再次使用,我們就說這塊內存泄漏了。
2、內存泄露的危害
從用戶使用程序的角度來看,內存泄漏本身不會產生什麼危害,作為一般的用戶,根本感覺不到內存泄漏的存在。真正有危害的`是內存泄漏的堆積,這會最終消耗盡系統所有的內存。從這個角度來說,一次性內存泄漏並沒有什麼危害,因為它不會堆積,而隱式內存泄漏危害性則非常大,因為較之於常發性和偶發性內存泄漏它更難被檢測到。存在內存泄漏問題的程序除了會佔用更多的內存外,還會使程序的性能急劇下降。對於伺服器而言,如果出現這種情況,即使系統不崩潰,也會嚴重影響使用。
3、內存泄露的檢測和回收
對於內存溢出之類的麻煩可能大家在編寫指針比較多的復雜的程序的時候就會遇到。在 Linux 或者 unix 下,C、C++語言是最使用工具。但是我們的 C++ 程序缺乏相應的手段來檢測內存信息,而只能使用 top 指令觀察進程的動態內存總額。而且程序退出時,我們無法獲知任何內存泄漏信息。
使用kill命令
使用Linux命令回收內存,我們可以使用Ps、Kill兩個命令檢測內存使用情況和進行回收。在使用超級用戶許可權時使用命令「Ps」,它會列出所有正在運行的程序名稱,和對應的進程號(PID)。Kill命令的工作原理是:向Linux操作系統的內核送出一個系統操作信號和程序的進程號(PID)。
應用例子:
為了高效率回收內存可以使用命令ps 參數v:
代碼如下:
[root@www ~]# ps v
PID TTY STAT TIME MAJFL TRS DRS RSS %MEM COMMAND
2542 tty1 Ss+ 0:00 0 8 1627 428 0.1 /sbin/mingetty tty1
2543 tty2 Ss+ 0:00 0 8 1631 428 0.1 /sbin/mingetty tty2
2547 tty3 Ss+ 0:00 0 8 1631 432 0.1 /sbin/mingetty tty3
2548 tty4 Ss+ 0:00 0 8 1627 428 0.1 /sbin/mingetty tty4
2574 tty5 Ss+ 0:00 0 8 1631 432 0.1 /sbin/mingetty tty5
2587 tty6 Ss+ 0:00 0 8 1627 424 0.1 /sbin/mingetty tty6
2657 tty7 Ss+ 1:18 12 1710 29981 7040 3.0 /usr/bin/Xorg :0 -br -a
2670 pts/2 Ss 0:01 2 682 6213 1496 0.6 -bash
3008 pts/4 Ss 0:00 2 682 6221 1472 0.6 /bin/bash
3029 pts/4 S+ 0:00 2 32 1783 548 0.2 ping 192.168.1.12
3030 pts/2 R+ 0:00 2 73 5134 768 0.3 ps v
然後如果想回收Ping命令的內存的話,使用命令:
代碼如下:
# Kill -9 3029
使用工具軟體
Memprof是一個非常具有吸引力且非常易於使用的軟體,它由Red Hat的Owen Talyor創立。這個工具是用於GNOME前端的Boehm-Demers-Weiser垃圾回收器。這個工具直接就可以執行,並且其工作起來無需對源代碼進行任何修改。在程序執行時,這個工具會以圖形化的方式顯示內存的使用情況。
相關介紹:Linux
嚴格來講,Linux這個詞本身只表示Linux內核,但人們已經習慣了用Linux來形容整個基於Linux內核,並且使用GNU 工程各種工具和資料庫的操作系統。
Linux擁有以下特性:類似於Unix的基本思想,支持完全免費與自由傳播,完全兼容POSIX1.0標准,支持多用戶、多任務、有著良好的界面、支持多種平台。Linux 能運行主要的UNIX工具軟體、應用程序和網路協議。它支持32位和64位硬體。Linux繼承了Unix以網路為核心的設計思想,是一個性能穩定的多用戶網路操作系統。
Linux有著許多不同的版本,但它們都使用了Linux內核。Linux可安裝在各種計算機硬體設備中,比如手機、平板電腦、路由器、視頻游戲控制台、台式計算機、大型機和超級計算機。
8. Linux進程通信實驗(共享內存通信,接上篇)
這一篇記錄一下共享內存實驗,需要linux的共享內存機制有一定的了解,同時也需要了解POSIX信號量來實現進程間的同步。可以參考以下兩篇博客: https://blog.csdn.net/sicofield/article/details/10897091
https://blog.csdn.net/ljianhui/article/details/10253345
實驗要求:編寫sender和receiver程序,sender創建一個共享內存並等待用戶輸入,然後把輸入通過共享內存發送給receiver並等待,receiver收到後把消息顯示在屏幕上並用同樣方式向sender發送一個over,然後兩個程序結束運行。
這個實驗的難點主要在於共享內存的創建和撤銷(涉及到的步驟比較多,需要理解各步驟的功能),以及實現兩個進程間的相互等待(使用信號量來實現,這里使用了有名信號量)
實驗心得:學習理解了linux的共享內存機制以及POSIX信號量機制。
兩個實驗雖然加強了對linux一些機制的理解,但是感覺對linux的學習還不夠,需要繼續學習。
9. 探討一下 Linux 共享內存的 N 種方式
關於 Linux 共享內存,寫得最好的應該是宋寶華的 《世上最好的共享內存》 一文。
本文可以說是對這篇文章的學習筆記,順手練習了一下 rust libc —— shichaoyuan/learn_rust/linux-shmipc-demo
按照宋寶華的總結,當前有四種主流的共享內存方式:
前兩種方式比較符合傳統的用法,共享內存做為進程間通信的媒介。
第三種方式更像是通過傳遞內存「句柄」進行數據傳輸。
第四種方式是為設備間傳遞數據設計,避免內存拷貝,直接傳遞內存「句柄」。
這里嘗試了一下第二種和第三種方式。
這套 API 應該是最普遍的 —— shm_open + mmap,本質上來說 Aeron 也是用的這種方式(關於 Aeron 可以參考 我之前的文章 )。
看一下 glibc 中 shm_open 函數的實現就一清二楚了:
shm_open 函數就是在 /dev/shm 目錄下建文件,該目錄掛載為 tmpfs,至於 tmpfs 可以簡單理解為存儲介質是內存的一種文件系統,更准確的理解可以參考官方文檔 tmpfs.txt 。
然後通過 mmap 函數將 tmpfs 文件映射到用戶空間就可以隨意操作了。
優點:
這種方式最大的優勢在於共享的內存是有「實體」(也就是 tmpfs 中的文件)的,所以多個進程可以很容易通過文件名這個信息構建共享內存結構,特別適合把共享內存做為通信媒介的場景(例如 Aeron )。
缺點:
如果非要找一個缺點的話,可能是,文件本身獨立於進程的生命周期,在使用完畢後需要注意刪除文件(僅僅 close 是不行的),否則會一直佔用內存資源。
memfd_create 函數的作用是創建一個匿名的文件,返回對應的 fd,這個文件當然不普通,它存活在內存中。更准確的理解可以參考官方文檔 memfd_create(2) 。
直觀理解,memfd_create 與 shm_open 的作用是一樣的,都是創建共享內存實體,只是 memfd_create 創建的實體是匿名的,這就帶了一個問題:如何讓其它進程獲取到匿名的實體?shm_open 方式有具體的文件名,所以可以通過打開文件的方式獲取,那麼對於匿名的文件怎麼處理呢?
答案是:通過 Unix Domain Socket 傳遞 fd。
rust 的 UDS 實現:
rust 在 std 中已經提供了 UDS 的實現,但是關於傳遞 fd 的 send_vectored_with_ancillary 函數還屬於 nightly-only experimental API 階段。所以這里使用了一個三方 crate —— sendfd ,坦白說可以自己實現一下,使用 libc 構建好 SCM_RIGHTS 數據,sendmsg 出去即可,不過細節還是挺多,我這里就放棄了。
這套 API 設計更靈活,直接拓展了我的思路,本來還是受限於 Aeron 的用法,如果在這套 API 的加持下,是否可以通過傳遞數據包內存塊(fd)真正實現零拷貝呢?
優點:
靈活。
缺點:
無