tft每日頭條

 > 生活

 > 查看linux 進程占用内存變化情況

查看linux 進程占用内存變化情況

生活 更新时间:2025-01-23 03:50:28

linux開發相關視頻解析:

初識Linux内核,進程通信能這麼玩

BAT面試必備:多線程、多進程、協程如何選擇及線程池如何最高效

linux内核,進程調度器的實現,完全公平調度器 CFS

一 進程空間分布概述

對于一個進程,其空間分布如下圖所示:

查看linux 進程占用内存變化情況(Linux進程地址空間與進程内存布局詳解)1

程序段(Text):程序代碼在内存中的映射,存放函數體的二進制代碼。

初始化過的數據(Data):在程序運行初已經對變量進行初始化的數據。

未初始化過的數據(BSS):在程序運行初未對變量進行初始化的數據。

棧 (Stack):存儲局部、臨時變量,函數調用時,存儲函數的返回指針,用于控制函數的調用和返回。在程序塊開始時自動分配内存,結束時自動釋放内存,其操作方式類似于數據結構中的棧。

堆 (Heap):存儲動态内存分配,需要程序員手工分配,手工釋放.注意它與數據結構中的堆是兩回事,分配方式類似于鍊表。

注:1.Text, BSS, Data段在編譯時已經決定了進程将占用多少VM

可以通過size,知道這些信息:

2. 正常情況下,Linux進程不能對用來存放程序代碼的内存區域執行寫操作,即程序代碼是以隻讀的方式加載到内存中,但它可以被多個進程安全的共享。

二 内核空間和用戶空間

Linux的虛拟地址空間範圍為0~4G,Linux内核将這4G字節的空間分為兩部分, 将最高的1G字節(從虛拟地址0xC0000000到0xFFFFFFFF)供内核使用,稱為“内核空間”。而将較低的3G字節(從虛拟地址0x00000000到0xBFFFFFFF)供各個進程使用,稱為“用戶空間。因為每個進程可以通過系統調用進入内核,因此,Linux内核由系統内的所有進程共享。于是,從具體進程的角度來看,每個進程可以擁有4G字節的虛拟空間。

Linux使用兩級保護機制:0級供内核使用,3級供用戶程序使用,每個進程有各自的私有用戶空間(0~3G),這個空間對系統中的其他進程是不可見的,最高的1GB字節虛拟内核空間則為所有進程以及内核所共享。 内核空間中存放的是内核代碼和數據,而進程的用戶空間中存放的是用戶程序的代碼和數據。不管是内核空間還是用戶空間,它們都處于虛拟空間中。 雖然内核空間占據了每個虛拟空間中的最高1GB字節,但映射到物理内存卻總是從最低地址(0x00000000),另外, 使用虛拟地址可以很好的保護 内核空間被用戶空間破壞,虛拟地址到物理地址轉換過程有操作系統和CPU共同完成(操作系統為CPU設置好頁表,CPU通過MMU單元進行地址轉換)。

:多任務操作系統中的每一個進程都運行在一個屬于它自己的内存沙盒中,這個 沙盒就是虛拟地址空間(virtual address space),在32位模式下,它總是一個4GB的内存地址塊。這些虛拟地址通過頁表(page table)映射到物理内存,頁表由操作系統維護并被處理器引用。每個進程都擁有一套屬于它自己的頁表。

進程内存空間分布如下圖所示:

查看linux 進程占用内存變化情況(Linux進程地址空間與進程内存布局詳解)2

通常32位Linux内核地址空間劃分0~3G為用戶空間,3~4G為内核空間

: 1.這裡是32位内核地址空間劃分,64位内核地址空間劃分是不同的

2. 現代的操作系統都處于32位保護模式下。每個進程一般都能尋址4G的物理空間。但是我們的物理内存一般都是幾百M,進程怎麼能獲得4G 的物理空間呢?這就是使用了虛拟地址的好處,通常我們使用一種叫做虛拟内存的技術來實現,因為可以使用硬盤中的一部分來當作内存使用 。

查看linux 進程占用内存變化情況(Linux進程地址空間與進程内存布局詳解)3

Linux系統對自身進行了劃分,一部分核心軟件獨立于普通應用程序,運行在較高的特權級别上,它們駐留在被保護的内存空間上,擁有訪問硬件設備的所有權限,Linux将此稱為内核空間。相對地,應用程序則是在“用戶空間”中運行。運行在用戶空間的應用程序隻能看到允許它們使用的部分系統資源,并且不能使用某些特定的系統功能,也不能直接訪問内核空間和硬件設備,以及其他一些具體的使用限制。将用戶空間和内核空間置于這種非對稱訪問機制下有很好的安全性,能有效抵禦惡意用戶的窺探,也能防止質量低劣的用戶程序的侵害,從而使系統運行得更穩定可靠。

内核空間在頁表中擁有較高的特權級(ring2或以下),因此隻要用戶态的程序試圖訪問這些頁,就會導緻一個頁錯誤(page fault)。在Linux中,内核空間是持續存在的,并且在所有進程中都映射到同樣的物理内存,内核代碼和數據總是可尋址的,随時準備處理中斷和系統調用。與之相反,用戶模式地址空間的映射随着進程切換的發生而不斷的變化,如下圖所示:

查看linux 進程占用内存變化情況(Linux進程地址空間與進程内存布局詳解)4

上圖中藍色區域表示映射到物理内存的虛拟地址,而白色區域表示未映射的部分。可以看出,Firefox使用了相當多的虛拟地址空間,因為它占用内存較多。

【文章福利】需要C/C Linux服務器架構師學習資料加群812855908(資料包括C/C ,Linux,golang技術,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒體,CDN,P2P,K8S,Docker,TCP/IP,協程,DPDK,ffmpeg等)

查看linux 進程占用内存變化情況(Linux進程地址空間與進程内存布局詳解)5

三 進程内存布局

Linux進程标準的内存段布局,如下圖所示,地址空間中的各個條帶對應于不同的内存段(memory segment),如:堆、棧之類的。

查看linux 進程占用内存變化情況(Linux進程地址空間與進程内存布局詳解)6

查看linux 進程占用内存變化情況(Linux進程地址空間與進程内存布局詳解)7

:這些段隻是簡單的虛拟内存地址空間範圍,與Intel處理器的段沒有任何關系。

幾乎每個進程的虛拟地址空間中各段的分布都與上圖完全一緻, 這就給遠程發掘程序漏洞的人打開了方便之門。一個發掘過程往往需要引用絕對内存地址:棧地址,庫函數地址等。遠程攻擊者必須依賴地址空間分布的一緻性,來探索出這些地址。如果讓他們猜個正着,那麼有人就會被整了。因此,地址空間的随機排布方式便逐漸流行起來,Linux通過對棧、内存映射段、堆的起始地址加上随機的偏移量來打亂布局。但不幸的是,32位地址空間相當緊湊,這給随機化所留下的空間不大,削弱了這種技巧的效果。

進程地址空間中最頂部的段是棧,大多數編程語言将之用于存儲函數參數和局部變量。調用一個方法或函數會将一個新的棧幀(stack frame)壓入到棧中,這個棧幀會在函數返回時被清理掉。由于棧中數據嚴格的遵守FIFO的順序,這個簡單的設計意味着不必使用複雜的數據結構來追蹤棧中的内容,隻需要一個簡單的指針指向棧的頂端即可,因此壓棧(pushing)和退棧(popping)過程非常迅速、準确。進程中的每一個線程都有屬于自己的棧。

通過不斷向棧中壓入數據,超出其容量就會耗盡棧所對應的内存區域,這将觸發一個頁故障(page fault),而被Linux的expand_stack()處理,它會調用acct_stack_growth()來檢查是否還有合适的地方用于棧的增長。如果棧的大小低于RLIMIT_STACK(通常為8MB),那麼一般情況下棧會被加長,程序繼續執行,感覺不到發生了什麼事情。這是一種将棧擴展到所需大小的常規機制。然而,如果達到了最大棧空間的大小,就會棧溢出(stack overflow),程序收到一個段錯誤(segmentation fault)。

:動态棧增長是唯一一種訪問未映射内存區域而被允許的情形,其他任何對未映射内存區域的訪問都會觸發頁錯誤,從而導緻段錯誤。一些被映射的區域是隻讀的,因此企圖寫這些區域也會導緻段錯誤。

内存映射段

在棧的下方是内存映射段,内核将文件的内容直接映射到内存。任何應用程序都可以通過Linux的mmap()系統調用或者Windows的CreateFileMapping()/MapViewOfFile()請求這種映射。内存映射是一種方便高效的文件I/O方式,所以它被用來加載動态庫。創建一個不對應于任何文件的匿名内存映射也是可能的,此方法用于存放程序的數據。在Linux中,如果你通過malloc()請求一大塊内存,C運行庫将會創建這樣一個匿名映射而不是使用堆内存。“大塊”意味着比MMAP_THRESHOLD還大,缺省128KB,可以通過mallocp()調整。

與棧一樣,堆用于運行時内存分配;但不同的是,堆用于存儲那些生存期與函數調用無關的數據。大部分語言都提供了堆管理功能。在C語言中,堆分配的接口是malloc()函數。如果堆中有足夠的空間來滿足内存請求,它就可以被語言運行時庫處理而不需要内核參與,否則,堆會被擴大,通過brk()系統調用來分配請求所需的内存塊。堆管理是很複雜的,需要精細的算法來應付我們程序中雜亂的分配模式,優化速度和内存使用效率。處理一個堆請求所需的時間會大幅度的變動。實時系統通過特殊目的分配器來解決這個問題。堆在分配過程中可能會變得零零碎碎,如下圖所示:

查看linux 進程占用内存變化情況(Linux進程地址空間與進程内存布局詳解)8

一般由程序員分配釋放, 若程序員不釋放,程序結束時可能由OS回收 。注意它與數據結構中的堆是兩回事,分配方式類似于鍊表。

BBS和數據段

在C語言中,BSS和數據段保存的都是靜态(全局)變量的内容。區别在于BSS保存的是未被初始化的靜态變量内容,他們的值不是直接在程序的源碼中設定的。BSS内存區域是匿名的,它不映射到任何文件。如果你寫static intcntActiveUsers,則cntActiveUsers的内容就會保存到BSS中去。

數據段保存在源代碼中已經初始化的靜态變量的内容。數據段不是匿名的,它映射了一部分的程序二進制鏡像,也就是源代碼中指定了初始值的靜态變量。所以,如果你寫static int cntActiveUsers=10,則cntActiveUsers的内容就保存在了數據段中,而且初始值是10。盡管數據段映射了一個文件,但它是一個私有内存映射,這意味着更改此處的内存不會影響被映射的文件。

你可以通過閱讀文件/proc/pid_of_process/maps來檢驗一個Linux進程中的内存區域。記住:一個段可能包含許多區域。比如,每個内存映射文件在mmap段中都有屬于自己的區域,動态庫擁有類似BSS和數據段的額外區域。有時人們提到“數據段”,指的是全部的數據段 BSS 堆。

你還可以通過nm和objdump命令來察看二進制鏡像,打印其中的符号,它們的地址,段等信息。最後需要指出的是,前文描述的虛拟地址布局在linux中是一種“靈活布局”,而且作為默認方式已經有些年頭了,它假設我們有值RLIMT_STACK。但是,當沒有該值得限制時,Linux退回到“經典布局”,如下圖所示:

查看linux 進程占用内存變化情況(Linux進程地址空間與進程内存布局詳解)9

C語言程序實例分析如下所示:

#include<stdio.h> #include <malloc.h> void print(char *,int); int main() { char *s1 = "abcde"; //"abcde"作為字符串常量存儲在常量區 s1、s2、s5擁有相同的地址 char *s2 = "abcde"; char s3[] = "abcd"; long int *s4[100]; char *s5 = "abcde"; int a = 5; int b =6;//a,b在棧上,&a>&b地址反向增長 printf("variables address in main function: s1=%p s2=%p s3=%p s4=%p s5=%p a=%p b=%p \n", s1,s2,s3,s4,s5,&a,&b); printf("variables address in processcall:n"); print("ddddddddd",5);//參數入棧從右至左進行,p先進棧,str後進 &p>&str printf("main=%p print=%p \n",main,print); //打印代碼段中主函數和子函數的地址,編譯時先編譯的地址低,後編譯的地址高main<print } void print(char *str,int p) { char *s1 = "abcde"; //abcde在常量區,s1在棧上 char *s2 = "abcde"; //abcde在常量區,s2在棧上 s2-s1=6可能等于0,編譯器優化了相同的常量,隻在内存保存一份 //而&s1>&s2 char s3[] = "abcdeee";//abcdeee在常量區,s3在棧上,數組保存的内容為abcdeee的一份拷貝 long int *s4[100]; char *s5 = "abcde"; int a = 5; int b =6; int c; int d; //a,b,c,d均在棧上,&a>&b>&c>&d地址反向增長 char *q=str; int m=p; char *r=(char *)malloc(1); char *w=(char *)malloc(1) ; // r<w 堆正向增長 printf("s1=%p s2=%p s3=%p s4=%p s5=%p a=%p b=%p c=%p d=%p str=%p q=%p p=%p m=%p r=%p w=%p \n", s1,s2,s3,s4,s5,&a,&b,&c,&d,&str,q,&p,&m,r,w); /* 棧和堆是在程序運行時候動态分配的,局部變量均在棧上分配。 棧是反向增長的,地址遞減;malloc等分配的内存空間在堆空間。堆是正向增長的,地址遞增。 r,w變量在棧上(則&r>&w),r,w所指内容在堆中(即r<w)。*/ }

附錄:

棧與堆的區别

查看linux 進程占用内存變化情況(Linux進程地址空間與進程内存布局詳解)10

,

更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!

查看全部

相关生活资讯推荐

热门生活资讯推荐

网友关注

Copyright 2023-2025 - www.tftnews.com All Rights Reserved