關於虛擬記憶體的分析

來源:互聯網
上載者:User

好久沒更新部落格了,最近被虛擬記憶體給搞糊塗了,翻書 google差不多半個月吧,爭取搞出點頭緒來,但是基礎知識不多說,大家看書看看什麼是虛擬空間吧,這篇文章重在是一個進程所佔虛擬空間的分析

先看top

top - 18:34:57 up 4 days,  4:20,  4 users,  load average: 0.00, 0.00, 0.00
Tasks: 114 total,   1 running, 113 sleeping,   0 stopped,   0 zombie
Cpu(s):  0.2%us,  0.2%sy,  0.0%ni, 99.7%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Mem:   4051424k total,  3612920k used,   438504k free,   200040k buffers
Swap:  8385920k total,        0k used,  8385920k free,  3114324k cached

在這裡重點介紹的是Swap,當實體記憶體空間不夠用的時候,進程的虛擬空間的內容會放到硬碟上的swap分區中,

[root@web-dev-146 ~]# cat /proc/swaps
Filename                                Type            Size    Used    Priority
/dev/sda3                               partition       8385920 0       -2

很明顯分了8g的大小也就是硬碟分區來存放進程虛擬空間內容資料

對於共用記憶體映射情況,缺頁例外處理常式首先在swap   cache中尋找目標頁(符合address_space以及位移量的物理頁),如果找到,則直接返回地址;如果沒有找到,則判斷該頁是否在交換區(swap   area),如果在,則執行一個換入操作;如果上述兩種情況都不滿足,處理常式將分配新的物理頁面,並把它插入到page   cache中。進程最終將更新進程頁表。 

一會通過執行個體我們來分析swap cache的作用

swap cached中的大小我們通過

free來看

             total       used       free     shared    buffers     cached
Mem:       4051424    3613052     438372          0     200072    3114368
-/+ buffers/cache:     298612    3752812
Swap:      8385920          0    8385920

說明讀取檔案佔用了這麼大的物理空間,用於緩衝已經開啟的檔案

倒沒必要釋放作業系統會根據需要多少記憶體就從cache釋放多少記憶體,所以不必操心,但是通過我們的例子你可以看到swap cache是不斷增長的那是因為我們用到了檔案對應,並且去讀檔案的內容

可以通過echo 3 > /proc/sys/vm/drop_caches 手動釋放

寫了一個c程式

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/mman.h>

int main()
{
int fd;
int i;
if ( (fd = open("/home/mongodb/shard200/fs_media_recommend.8", O_RDWR|O_CREAT, S_IRWXU)) < 0){
   printf("open file wrong!");
   return 0;
}

struct stat file_stat;
if ( fstat( fd, &file_stat) < 0 )
{
   printf(" fstat wrong");
   return 0;
}

int *start_fp;
if( ( start_fp = (int *)mmap(NULL, 2146435072, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0 )) == MAP_FAILED)
{
   printf("mmap wrong");
   return 0;

}
for(i=0;i<10000000;i++){
printf("%d\n", start_fp[i]);
}
/*msync( start_fp, file_stat.st_size, MS_ASYNC);

if ( munmap( start_fp, file_stat.st_size ) < 0 )
{
   printf("munmap wrong");
   return 0;
}*/
sleep(100000);
}

其中我們用到了mmap檔案對應,故意sleep這麼久我們可以分析下進程的虛擬位址的資訊

top - 18:43:07 up 4 days,  4:28,  4 users,  load average: 0.15, 0.05, 0.02
Tasks:   1 total,   1 running,   0 sleeping,   0 stopped,   0 zombie
Cpu0  :  0.0%us,  0.0%sy,  0.0%ni,100.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Cpu1  :  0.0%us,  0.0%sy,  0.0%ni,100.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Mem:   4051424k total,  3612804k used,   438620k free,   200052k buffers
Swap:  8385920k total,        0k used,  8385920k free,  3114332k cached
 Cumulative time On
  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  SWAP CODE DATA COMMAND                                                 
16955 root      16   0 2050m  25m  25m R  0.0  0.6   0:25.84 2.0g    4  120 test9                                                   

當運行改程式,會發現進程的res在不斷增大,但是VIRT和SWAP以及上面的Swap沒有絲毫變化

大家可以試著去掉我從映射讀取內容那塊代碼,可以見到一上來VIRT和SWAP就已經確定了大小,該大小是在進程載入後分配了虛擬空間,當然並不是真的分了2g這麼大的空間,因為虛擬空間對應的Swap並沒有發生變化,說明虛擬空間內容沒有寫到磁碟中,其實我們看下進程虛擬空間的分析

[root@web-dev-146 ~]# ps -ef | grep test9
root     16968  9017 19 18:47 pts/2    00:00:01 ./test9
root     16970 13123  0 18:47 pts/1    00:00:00 grep test9
[root@web-dev-146 ~]# cat /proc/16968/maps
00400000-00401000 r-xp 00000000 08:02 6305715                            /root/test9
00600000-00601000 rw-p 00000000 08:02 6305715                            /root/test9
3c5a400000-3c5a41c000 r-xp 00000000 08:02 1405202                        /lib64/ld-2.5.so
3c5a61b000-3c5a61c000 r--p 0001b000 08:02 1405202                        /lib64/ld-2.5.so
3c5a61c000-3c5a61d000 rw-p 0001c000 08:02 1405202                        /lib64/ld-2.5.so
3c5a800000-3c5a94d000 r-xp 00000000 08:02 1405203                        /lib64/libc-2.5.so
3c5a94d000-3c5ab4d000 ---p 0014d000 08:02 1405203                        /lib64/libc-2.5.so
3c5ab4d000-3c5ab51000 r--p 0014d000 08:02 1405203                        /lib64/libc-2.5.so
3c5ab51000-3c5ab52000 rw-p 00151000 08:02 1405203                        /lib64/libc-2.5.so
3c5ab52000-3c5ab57000 rw-p 3c5ab52000 00:00 0
2ad9f31db000-2ad9f31dc000 rw-p 2ad9f31db000 00:00 0
2ad9f31ed000-2ad9f31ef000 rw-p 2ad9f31ed000 00:00 0
2ad9f31ef000-2ada730ef000 rw-s 00000000 08:05 60686353                   /home/mongodb/shard200/fs_media_recommend.8
2ada730ef000-2ada730f0000 rw-p 2ada730ef000 00:00 0
7fffd6e4f000-7fffd6e64000 rw-p 7ffffffea000 00:00 0                      [stack]
ffffffffff600000-ffffffffffe00000 ---p 00000000 00:00 0                  [vdso]

這就是該進程對應的虛擬位址空間,可以很清楚的看到虛擬空間對應了我代碼裡面檔案的映射關係,大小是多少呢

16968:   ./test9
0000000000400000      4K r-x--  /root/test9
0000000000600000      4K rw---  /root/test9
0000003c5a400000    112K r-x--  /lib64/ld-2.5.so
0000003c5a61b000      4K r----  /lib64/ld-2.5.so
0000003c5a61c000      4K rw---  /lib64/ld-2.5.so
0000003c5a800000   1332K r-x--  /lib64/libc-2.5.so
0000003c5a94d000   2048K -----  /lib64/libc-2.5.so
0000003c5ab4d000     16K r----  /lib64/libc-2.5.so
0000003c5ab51000      4K rw---  /lib64/libc-2.5.so
0000003c5ab52000     20K rw---    [ anon ]
00002ad9f31db000      4K rw---    [ anon ]
00002ad9f31ed000      8K rw---    [ anon ]
00002ad9f31ef000 2096128K rw-s-  /home/mongodb/shard200/fs_media_recommend.8
00002ada730ef000      4K rw---    [ anon ]
00007fffd6e4f000     84K rw---    [ stack ]
ffffffffff600000   8192K -----    [ anon ]
 total          2107968K

很清楚吧,大小就是我代碼裡面映射的大小,大家可以通過一下更深刻瞭解一下虛擬空間的資訊

[root@web-dev-146 ~]# cat /proc/16968/status
Name:   test9
State:  S (sleeping)
SleepAVG:       98%
Tgid:   16968
Pid:    16968
PPid:   9017
TracerPid:      0
Uid:    0       0       0       0
Gid:    0       0       0       0
FDSize: 256
Groups: 0 1 2 3 4 6 10
VmPeak:  2099776 kB
VmSize:  2099776 kB
VmLck:         0 kB
VmHWM:     39440 kB
VmRSS:     39440 kB
VmData:       36 kB
VmStk:        84 kB
VmExe:         4 kB
VmLib:      1444 kB
VmPTE:       116 kB
StaBrk: 1ede2000 kB
Brk:    1ede2000 kB
StaStk: 7fffd6e63850 kB
Threads:        1
SigQ:   1/36864
SigPnd: 0000000000000000
ShdPnd: 0000000000000000
SigBlk: 0000000000000000
SigIgn: 0000000000000000
SigCgt: 0000000000000000
CapInh: 0000000000000000
CapPrm: 00000000fffffeff
CapEff: 00000000fffffeff
Cpus_allowed:   00000000,00000000,00000000,00000000,00000000,00000000,00000000,0000000f
Mems_allowed:   00000000,00000001

我們可以看到虛擬空間是2099776kB大小,這和我們top該進程對應的資料是一致的,

上面的例子為了說明virt虛擬記憶體大小並不是其實佔用了實體記憶體後者磁碟空間的大小,這個大小的確定是由於進程在實體記憶體中放了一份映射表,沒分配一個進程總是又這麼一個映射資料結構即

載入關於進程虛擬位址空間的頁面時,一系列的vm_area_struct將自動產生,每一個vm_area_struct描述進程的一部分,如執行代碼、資料等。Linux虛擬儲存管理支援了多數標準的虛擬記憶體操作,如讀取、關閉、共用、缺頁等。一旦vm_area_struct結構產生,就可以通過該結構中的指向vm_operation_struct的指標進行虛擬記憶體操作了。

3所示,為虛存管理資料結構之間的關係。

圖 3        虛擬儲存管理的資料結構關係

這個結構引用一下網上的,這個結構是不可避免的是真正佔用記憶體空間的當然不會太大,它只記錄虛擬空間分配內容中的頭和尾的資訊,所以佔用虛擬空間大小一算就知道了

剛才我們提到過VIRT放到SWAP分區的所以對於該進程剛開始初始化的時候我們發現VIRT和SWAP空間大小一致,都是虛擬,

但是當我們讀取對應檔的內容時,這時候通過頁面中斷,我們對應檔的內容會載入到真正的實體記憶體中,就是我們上面做的實驗,我們會發現實體記憶體RES 在不斷的增加,但是由於有一些內容已經匯入到了實體記憶體中,所以作業系統會對SWAP磁碟空間進行釋放,看下面

  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  SWAP CODE DATA COMMAND                                                 
 9193 root      15   0 3974m 3.0g  640 S  0.0 19.0  28:50.33 933m  328 3.9g redis-server      

這個時候我們發現VIRT = SWAP+RES的大小,很容易理解,既然你實體記憶體已經存放了資料,當然我要空出那些沒必要的冗餘空間用來作別的          

先到這我會把想到的繼續補充進去                         

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.