『壹』 linux:誰能給我解釋下虛擬地址和物理地址的聯系
這個問題很大。。。。我盡自己所能給你解釋一下吧,如果你不能完全看懂,以後可以回頭再翻翻來看。關於虛擬內存的事情,大概是這樣的:
首先你要明確什麼是虛擬內存。虛擬內存實際上是操作系統對於內存管理的一種方式,比如說,對每個程序而言,它的內存編址都從0x00到0xff,但是實際上,這些內存對應的物理地址,應用程序本身是無法知道的,在這里就可以理解成操作系統對內存管理的一層抽象。
比如,可能進程init的虛擬地址0x00對應了物理地址的0x10,而kthreadd的虛擬地址0x00對應物理地址0x20,etc.
而且虛擬內存也是一種有效的進程間隔離的方式,極大的提升了進程的安全性和操作系統的穩定性,也就是我一個進程不管做什麼,都是在它自己的地址空間里做的,不會影響到其他進程和OS。
當然這是理想情況,實際上還有進程間通信啦之類,這就不在這個問題的范圍之內了。
而具體怎麼把這些虛擬地址對應到物理地址上,這是操作系統做的事情,估計這個也就是你的問題。
----以上是背景1-----
然後我要明確一下:地址匯流排4位的意思是說內存用4個bit位來表達地址,所以能夠index的地址位就是2^0-2^4,也就是0x0到0xf,就是16個bit的內存空間。
然後我們再來細化一下你的例子,就比方說在你的16bit的內存的機器上有1個OS,上面跑著2個程序。一般來說OS會保留地址的高位,比如11-15bit的位置,作為kernel space;然後0-10bit是user space。
在以上的前提下,虛擬內存的效果是:在每一個程序看來,這個程序都有0x0到0xf的地址可以用,並且它們的0xb-0xf都是shared kernel space,然後0x0-0xa都是自己的user space,這樣彷彿就有了32個bit的地址一樣。這就是你所謂的是用虛擬地址可以使總的地址操作物理地址。至於os是怎麼做到這點的,繼續往下看。
-----以上是背景2-----
操作系統對每一個進程有一個進程式控制制塊,叫PCB,Process Control Block,里邊存儲了每一個進程的進程信息,比如說寄存器,file descriptor,還有我們最關心的內存映射信息。每一個進程有一個遞增的id號,叫pid,也就是Process IDentifier.
-----以上是背景3-----
進程間切換,也就是說,比如說你一個系統只有1個CPU,但是有兩個進程要跑,而且要讓我們看起來好像是兩個進程同時在跑一樣。為什麼我要提到這個呢,後面繼續看。
-----以上是背景4-----
好,現在來講如何把虛擬地址映射到物理地址。從程序的角度來看,從malloc開始講起,比如,在某一時刻,一個進程調用了malloc,在堆(heap)上申請了2bits的空間。實際上這個行為的流程是,程序調用malloc,進入內核模式之後,調用mmap,如果成功,操作系統會從物理地址上取一塊2bits的內存,交給應用程序編入虛擬地址空間。更詳細一點說,每個進程對內存管理是一個紅黑樹的結構,也就是說,在每一個進程的PCB,里維護了一顆紅黑樹,然後動態的將所有的新分配的內存加到這個紅黑樹里邊,以保證程序對每一塊內存的訪問時間是差不多的。然後不知道你們教材中有沒有提到頁表(page table),頁表也是PCB中的一項,你們教材中應該會對頁表有詳細的講解,將如何對內存的地址進行換算,之類的。然後你要明確,頁表實際上是紅黑樹的cache,這樣可以加速程序對於常用的內存的訪問速度。
以上是操作系統對內存管理的一個大致概括,就是一塊物理的內存如何映射成為一塊虛擬的內存。
我在背景2中說,兩個程序都看到自己有16個bit的虛擬地址,總共有32bit,但是實際上硬體只有16bits,也就是說,不管你在紅黑樹和頁表中怎麼映射,一定會有沖突發生,比如,可能物理地址的0x02對應了進程1中的0x04,又在進程2的PCB中映射到了pid2的虛擬地址位0x06上。操作系統如何解決這個矛盾呢,首先在進程pid 1運行的時候,這個0x02對應的是pid1中的0x04;然後這個時候進程切換發生了,pid 2開始運行。當pid2需要用到它的0x04時,os發現0x02這個地址在pid1中也有映射,於是它就把0x02這個地址上的內容存到硬碟上的一個叫swap的空間內,然後把這個地址交給pid2使用。這樣就達到了擴大虛擬地址的效果。
但是這樣做是有代價的,因為一旦這個page被swap出去,那麼在pid1再來調用的時候會發生一系列的miss,從L1 cache miss到 L2 cache miss到L3 cache miss,然後頁表miss,memory miss,會對程序的性能造成極大的影響。影響有多大呢,平均來說:
L1 cache hit: 0.5ns
L2 cache hit: 7ns
主內存引用:100ns
順序從內存中讀取1MB:250,000ns
硬碟尋道:10,000,000ns
從硬碟上順序讀取1MB:30,000,000ns
所以你就可以知道這種行為是以極大的性能為代價的。
----講完啦-----
總的來說這個很大的話題,我剛才所寫的東西的就是試圖讓你對虛擬內存這個東西有一個基本的概念,然後大致的了解內存是如何映射的。就我現在能想到的,對這個虛擬內存話題的討論還包括多級頁表,進程間隔離&通信以及memory fragment。
個人水平有限,如果以上有什麼地方說錯的或者遺漏的,還請各位多多補充和批評,謝謝。
『貳』 Linux進程虛擬地址空間的分布,以及堆和棧的區別
一、具體分布如圖所示:
二、關於堆和棧
(1)分配方式:
棧:由編譯器自動分配釋放,存放函數的參數回值,局部變數的值等。其操作方式類似於數據結構中的棧。
堆: 一般由程序員分配釋放,它的分配方式類似於鏈表。
(2)申請後系統的響應:
棧:只要所申請的空間小於棧的剩餘空間,則系統為程序分配內存,否則棧溢出。
堆:操作系統有一個記錄空閑內存地址的鏈表,當系統收到程序的申請時,遍歷該鏈表,找出第一個大於所申請空間的節點,然後將其從鏈表中刪除並分配,如果沒用完,則系統會把多餘的重新放回到鏈表中。
(3)申請大小的限制:
棧:棧答是高地址向低地址擴展的連續內存,棧的大小一般是2M;
堆:堆是低地址向高地址擴展的不連續內存,堆的大小與計算機有效的虛擬內存有關系。
(4)申請效率:
棧:由系統自動分配,速度較快;
堆:速度慢,容易產生內存碎片;
關於Linux命令的介紹,看看《linux就該這么學》,具體關於這一章地址3w(dot)linuxprobe/chapter-02(dot)html.
『叄』 如何查看Linux內存中的程序所有堆的地址
linux 下面查看內存有多種渠道,比如通過命令 ps ,top,free 等,比如通過/proc系統,一般需要比較詳細和精確地知道整機內存/某個進程內存的使用情況,最好通過/proc 系統,下面介紹/proc系統下內存相關的幾個文件
單個進程的內存查看 cat /proc/[pid] 下面有幾個文件: maps , smaps, status
maps 文件可以查看某個進程的代碼段、棧區、堆區、動態庫、內核區對應的虛擬地址,如果你還不了解linux進程的內存空間,可以參考這里。
下圖是maps文件內存示例
Develop>cat /proc/self/maps
00400000-0040b000 r-xp 00000000 fd:00 48 /mnt/cf/orig/root/bin/cat
0060a000-0060b000 r--p 0000a000 fd:00 48 /mnt/cf/orig/root/bin/cat
0060b000-0060c000 rw-p 0000b000 fd:00 48 /mnt/cf/orig/root/bin/cat 代碼段
0060c000-0062d000 rw-p 00000000 00:00 0 [heap] 堆區
7f1fff43b000-7f1fff5d4000 r-xp 00000000 fd:00 861 /mnt/cf/orig/root/lib64/libc-2.15.so
7f1fff5d4000-7f1fff7d3000 ---p 00199000 fd:00 861 /mnt/cf/orig/root/lib64/libc-2.15.so
7f1fff7d3000-7f1fff7d7000 r--p 00198000 fd:00 861 /mnt/cf/orig/root/lib64/libc-2.15.so
7f1fff7d7000-7f1fff7d9000 rw-p 0019c000 fd:00 861 /mnt/cf/orig/root/lib64/libc-2.15.so
7f1fff7d9000-7f1fff7dd000 rw-p 00000000 00:00 0
7f1fff7dd000-7f1fff7fe000 r-xp 00000000 fd:00 2554 /mnt/cf/orig/root/lib64/ld-2.15.so
7f1fff9f9000-7f1fff9fd000 rw-p 00000000 00:00 0
7f1fff9fd000-7f1fff9fe000 r--p 00020000 fd:00 2554 /mnt/cf/orig/root/lib64/ld-2.15.so
7f1fff9fe000-7f1fff9ff000 rw-p 00021000 fd:00 2554 /mnt/cf/orig/root/lib64/ld-2.15.so
7f1fff9ff000-7f1fffa00000 rw-p 00000000 00:00 0
7fff443de000-7fff443ff000 rw-p 00000000 00:00 0 [stack] 用戶態棧區
7fff443ff000-7fff44400000 r-xp 00000000 00:00 0 [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall] 內核區
有時候可以通過不斷查看某個進程的maps文件,通過查看其虛擬內存(堆區)是否不停增長來簡單判斷進程是否發生了內存溢出。
maps文件只能顯示簡單的分區,smap文件可以顯示每個分區的更詳細的內存佔用數據
下圖是smaps文件內存示例, 實際顯示內容會將每一個區都顯示出來,下面我只拷貝了代碼段和堆區,
每一個區顯示的內容項目是一樣的,smaps文件各項含義可以參考這里
Develop>cat /proc/self/smaps
00400000-0040b000 r-xp 00000000 fd:00 48 /mnt/cf/orig/root/bin/cat
Size: 44 kB 虛擬內存大小
Rss: 28 kB 實際使用物理內存大小
Pss: 28 kB
Shared_Clean: 0 kB 頁面被改,則是dirty,否則是clean,頁面引用計數>1,是shared,否則是private
Shared_Dirty: 0 kB
Private_Clean: 28 kB
Private_Dirty: 0 kB
Referenced: 28 kB
Anonymous: 0 kB
AnonHugePages: 0 kB
Swap: 0 kB 處於交換區的頁面大小
KernelPageSize: 4 kB 操作系統一個頁面大小
MMUPageSize: 4 kB 體系結構MMU一個頁面大小
Locked: 0 kB
0060c000-0062d000 rw-p 00000000 00:00 0 [heap]
Size: 132 kB
Rss: 8 kB
Pss: 8 kB
Shared_Clean: 0 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 8 kB
Referenced: 8 kB
Anonymous: 8 kB
AnonHugePages: 0 kB
Swap: 0 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Locked: 0 kB
下圖是status文件內存示例, 加粗部分是內存相關的統計,
Develop>cat /proc/24475/status
Name: netio 可執行程序的名字
State: R (running) 任務狀態,運行/睡眠/僵死
Tgid: 24475 線程組號
Pid: 24475 進程id
PPid: 19635 父進程id
TracerPid: 0
Uid: 0 0 0 0
Gid: 0 0 0 0
FDSize: 256 該進程最大文件描述符個數
Groups: 0
VmPeak: 6330708 kB 內存使用峰值
VmSize: 268876 kB 進程虛擬地址空間大小
VmLck: 0 kB 進程鎖住的物理內存大小,鎖住的物理內存無法交換到硬碟
VmHWM: 16656 kB
VmRSS: 11420 kB 進程正在使用的物理內存大小
VmData: 230844 kB 進程數據段大小
VmStk: 136 kB 進程用戶態棧大小
VmExe: 760 kB 進程代碼段大小
VmLib: 7772 kB 進程使用的庫映射到虛擬內存空間的大小
VmPTE: 120 kB 進程頁表大小
VmSwap: 0 kB
Threads: 5
SigQ: 0/63346
SigPnd: 0000000000000000
ShdPnd: 0000000000000000
SigBlk: 0000000000000000
SigIgn: 0000000001000000
SigCgt: 0000000180000000
CapInh: 0000000000000000
CapPrm: ffffffffffffffff
CapEff: ffffffffffffffff
CapBnd: ffffffffffffffff
Cpus_allowed: 01
Cpus_allowed_list: 0
Mems_allowed: 01
Mems_allowed_list: 0
voluntary_ctxt_switches: 201
nonvoluntary_ctxt_switches: 909
可以看到,linux下內存佔用是一個比較復雜的概念,不能
簡單通過一個單一指標就判斷某個程序「內存消耗」大小,原因有下面2點:
進程所申請的內存不一定真正會被用到(malloc或mmap的實現)
真正用到了的內存也不一定是只有該進程自己在用 (比如動態共享庫)
關於內存的使用分析及本文幾個命令的說明也可以參考這里
下面是查看整機內存使用情況的文件 /proc/meminfo
Develop>cat /proc/meminfo
MemTotal: 8112280 kB 所有可用RAM大小 (即物理內存減去一些預留位和內核的二進制代碼大小)
MemFree: 4188636 kB LowFree與HighFree的總和,被系統留著未使用的內存
Buffers: 34728 kB 用來給文件做緩沖大小
Cached: 289740 kB 被高速緩沖存儲器(cache memory)用的內存的大小
(等於 diskcache minus SwapCache )
SwapCached: 0 kB 被高速緩沖存儲器(cache memory)用的交換空間的大小
已經被交換出來的內存,但仍然被存放在swapfile中。
用來在需要的時候很快的被替換而不需要再次打開I/O埠
Active: 435240 kB 在活躍使用中的緩沖或高速緩沖存儲器頁面文件的大小,
除非非常必要否則不會被移作他用
Inactive: 231512 kB 在不經常使用中的緩沖或高速緩沖存儲器頁面文件的大小,可能被用於其他途徑.
Active(anon): 361252 kB
Inactive(anon): 120688 kB
Active(file): 73988 kB
Inactive(file): 110824 kB
Unevictable: 0 kB
Mlocked: 0 kB
SwapTotal: 0 kB 交換空間的總大小
SwapFree: 0 kB 未被使用交換空間的大小
Dirty: 0 kB 等待被寫回到磁碟的內存大小
Writeback: 0 kB 正在被寫回到磁碟的內存大小
AnonPages: 348408 kB 未映射頁的內存大小
Mapped: 33600 kB 已經被設備和文件等映射的大小
Shmem: 133536 kB
Slab: 55984 kB 內核數據結構緩存的大小,可以減少申請和釋放內存帶來的消耗
SReclaimable: 25028 kB 可收回Slab的大小
SUnreclaim: 30956 kB 不可收回Slab的大小(SUnreclaim+SReclaimable=Slab)
KernelStack: 1896 kB 內核棧區大小
PageTables: 8156 kB 管理內存分頁頁面的索引表的大小
NFS_Unstable: 0 kB 不穩定頁表的大小
Bounce: 0 kB
WritebackTmp: 0 kB
CommitLimit: 2483276 kB
Committed_AS: 1804104 kB
VmallocTotal: 34359738367 kB 可以vmalloc虛擬內存大小
VmallocUsed: 565680 kB 已經被使用的虛擬內存大小
VmallocChunk: 34359162876 kB
HardwareCorrupted: 0 kB
HugePages_Total: 1536 大頁面數目
HugePages_Free: 0 空閑大頁面數目
HugePages_Rsvd: 0
HugePages_Surp: 0
Hugepagesize: 2048 kB 大頁面一頁大小
DirectMap4k: 10240 kB
DirectMap2M: 8302592 kB
『肆』 Linux的內核空間和用戶空間是如何劃分的(以32位系統為例)
Linux將4G的地址劃分為用戶空間和內核空間兩部分。在Linux內核的低版本中(2.0.X),通常0-3G為用戶空間,3G-4G為內核空間。這個分界點是可以可以改動的。
正是這個分界點的存在,限制了Linux可用的最大內存為2G.而且要通過重編內核,調整這個分界點才能達到。實際上還可以有更好的方法來解決這個問題。由於內核空間與用戶空間互不重合,所以可以用段機制提供的保護功能來保護內核級代碼。
2.2.X版的內核對此進行了改動。這樣內核空間擴張到了4G。從表面上看內核的基地址變為了0,但實際上,內核通常仍在虛址3G以上。
用戶空間在2.2.X中從直觀上變為0-4G,讓人迷惑,不是可以直接訪問內核了?
其實不然,同過使用頁機制提供的保護,阻止了用戶程序訪問內核空間。
windows是使用的一個開關設置的,一般是1G,設置過開關之後,用花空間就可以達到3G
另外,附上一片文章吧,這個是64位系統上面的。。。希望能給你啟發~~~試著編譯下內核吧!
http://www.linuxidc.com/Linux/2011-03/33764.htm
『伍』 怎麼查看linux 系統的內存分布
top命令能顯示系統復內制存。
目前常用的Linux下查看內容的專用工具是free命令。
下面是對內存查看free命令輸出內容的解釋:
total:總計物理內存的大小。
used:已使用多大。
free:可用有多少。
Shared:多個進程共享的內存總額。
Buffers/cached:磁碟緩存的大小。