Linux02進程內存管理

1.進程地址空間

? ?1.1程序的結構與進程的結構

? ? ? ?[root@localhost demo]# size test



? text ? data ? ?bss ? ?dec ? ?hex filename

? ? 1193 ? ?492 ? ? 16 ? 1701 ? ?6a5 test

? ? ? ? 一個可執行程序包含三個部分:

? ? ? ? 代碼段:主要存放指令,操作以及只讀的常量數據例如字符串常量。

? ? ? ? 數據段:全局或者靜態的已經初始化的變量

? ? ? ? BSS段:全局或者靜態的未初始化的變量

? ? ? ? 執行一個程序要運行,需要將程序加載到內存(磁盤有專門的讀寫驅動,但是速度比較慢,內存可有cpu直接訪問讀寫,比磁盤速度要快)

? ?

名稱速度
CPU寄存器1ns
cache1ns~10ns
DRAM100ns
磁盤10ss
? ? ? 進程:進程是操作系統最小的資源管理單元。一個程序運行,必然要為其創建一個進程有生命周期的。一個進程是執行的程序段。

? ? ? ? ? ? ? ? 其資源分為內核資源和用戶資源。內核資源是PCB---進程控制塊,也就是一個結構體,負責管理進程所有資源。

? ? ? ? ? ? ? ? mm_struct指向該進程相關的內存資源:從低到高地址分為:代碼段->數據段->BSS段->堆段->棧段

? ? ? ? ? ? ? ? 在執行程序時,系統首先在內核空間創建一個進程,為這個進程申請一個進程控制塊PCB(task_struct),用于管理整個進城的所有資源。

? ?? 代碼段,數據段,BSS段,直接從磁盤拷貝到當前內存空間,大小相等。

? ?? 動態的空間:堆和棧空間,以及mmap段(主要是映射其他庫的相關信息)

? ? ? ? ? ? ? ? 命令:pmap 進程號或者cat /proc/進程號/maps

? ? ? ? ? ? ? ? ? ? ? ?[root@localhost proc]# cat 31281/maps
00400000-004d4000 r-xp 00000000 08:02 390951 ? ? ? ? ? ? ? ? ? ? ? ? ? ? /bin/bash
006d3000-006dd000 rw-p 000d3000 08:02 390951 ? ? ? ? ? ? ? ? ? ? ? ? ? ? /bin/bash
006dd000-006e2000 rw-p 00000000 00:00 0?
008dc000-008e5000 rw-p 000dc000 08:02 390951 ? ? ? ? ? ? ? ? ? ? ? ? ? ? /bin/bash
00b45000-00ba8000 rw-p 00000000 00:00 0 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?[heap]
32c0c00000-32c0c20000 r-xp 00000000 08:02 781828 ? ? ? ? ? ? ? ? ? ? ? ? /lib64/ld-2.12.so
32c0e1f000-32c0e20000 r--p 0001f000 08:02 781828 ? ? ? ? ? ? ? ? ? ? ? ? /lib64/ld-2.12.so
32c0e20000-32c0e21000 rw-p 00020000 08:02 781828 ? ? ? ? ? ? ? ? ? ? ? ? /lib64/ld-2.12.so
32c0e21000-32c0e22000 rw-p 00000000 00:00 0?
32c1000000-32c1002000 r-xp 00000000 08:02 782740 ? ? ? ? ? ? ? ? ? ? ? ? /lib64/libdl-2.12.so
32c1002000-32c1202000 ---p 00002000 08:02 782740 ? ? ? ? ? ? ? ? ? ? ? ? /lib64/libdl-2.12.so
32c1202000-32c1203000 r--p 00002000 08:02 782740 ? ? ? ? ? ? ? ? ? ? ? ? /lib64/libdl-2.12.so
32c1203000-32c1204000 rw-p 00003000 08:02 782740 ? ? ? ? ? ? ? ? ? ? ? ? /lib64/libdl-2.12.so
32c1400000-32c158b000 r-xp 00000000 08:02 782725 ? ? ? ? ? ? ? ? ? ? ? ? /lib64/libc-2.12.so
32c158b000-32c178a000 ---p 0018b000 08:02 782725 ? ? ? ? ? ? ? ? ? ? ? ? /lib64/libc-2.12.so
32c178a000-32c178e000 r--p 0018a000 08:02 782725 ? ? ? ? ? ? ? ? ? ? ? ? /lib64/libc-2.12.so
32c178e000-32c178f000 rw-p 0018e000 08:02 782725 ? ? ? ? ? ? ? ? ? ? ? ? /lib64/libc-2.12.so
32c178f000-32c1794000 rw-p 00000000 00:00 0?
3e6a000000-3e6a01d000 r-xp 00000000 08:02 781958 ? ? ? ? ? ? ? ? ? ? ? ? /lib64/libtinfo.so.5.7
3e6a01d000-3e6a21c000 ---p 0001d000 08:02 781958 ? ? ? ? ? ? ? ? ? ? ? ? /lib64/libtinfo.so.5.7
3e6a21c000-3e6a220000 rw-p 0001c000 08:02 781958 ? ? ? ? ? ? ? ? ? ? ? ? /lib64/libtinfo.so.5.7
3e6a220000-3e6a221000 rw-p 00000000 00:00 0?
7f2a4f326000-7f2a551b7000 r--p 00000000 08:02 914111 ? ? ? ? ? ? ? ? ? ? /usr/lib/locale/locale-archive
7f2a551b7000-7f2a551c3000 r-xp 00000000 08:02 781857 ? ? ? ? ? ? ? ? ? ? /lib64/libnss_files-2.12.so
7f2a551c3000-7f2a553c3000 ---p 0000c000 08:02 781857 ? ? ? ? ? ? ? ? ? ? /lib64/libnss_files-2.12.so
7f2a553c3000-7f2a553c4000 r--p 0000c000 08:02 781857 ? ? ? ? ? ? ? ? ? ? /lib64/libnss_files-2.12.so
7f2a553c4000-7f2a553c5000 rw-p 0000d000 08:02 781857 ? ? ? ? ? ? ? ? ? ? /lib64/libnss_files-2.12.so
7f2a553c5000-7f2a553c8000 rw-p 00000000 00:00 0?
7f2a553cc000-7f2a553ce000 rw-p 00000000 00:00 0?
7f2a553ce000-7f2a553d5000 r--s 00000000 08:02 914369 ? ? ? ? ? ? ? ? ? ? /usr/lib64/gconv/gconv-modules.cache
7f2a553d5000-7f2a553d6000 rw-p 00000000 00:00 0?
7fffc0a71000-7fffc0a86000 rw-p 00000000 00:00 0 ? ? ? ? ? ? ? ? ? ? ? ? ?[stack]

7fffc0b0a000-7fffc0b0b000 r-xp 00000000 00:00 0 ? ? ? ? ? ? ? ? ? ? ? ? ?[vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 ? ? ? ? ? ? ? ? ?[vsyscall]

? ? ? ? ? ? ? ? ?所看到的地址不是物理地址,都是虛擬地址。出于對資源的保護,一個程序并不需要立即將所有的資源全部加載到內存,而是實際上可采用寫時申請的方法。而且保護系統,很多用戶非法訪問不會造成內核的崩潰。

? ? ?1.2虛擬地址空間的申請

? ? ? ? ? ? ? 32位平臺下,一個進程擁有4G的虛擬地址,這個地址如何來分配和使用呢

大笑

  • ?代碼段,數據段,BSS段,這三個部分直接從磁盤拷貝到內存,起始地址在當前的32位平臺下的地址為0x08048000.
  • ?堆棧。是動態變化
  • mmap映射的文件
  • 棧段
  • 高地址1G空間,僅供內核映射處理,用戶空間不能直接處理
    內核空間1G
    gap間隙為了安全
    高地址向低地址增長
    map映射區域
    ?
    gap間隙為了安全
    BSS?
    數據段?
    代碼段?

  • 堆和棧的起始地址是隨機產生的,其目的是為了避免安全漏洞。但是可以指定在堆中申請空間的起始地址(brk/sbrk函數);
    #include<stdio.h>
    #include<stdlib.h>

    #include<stdio.h>
    #include<stdlib.h>


    int main(int argc,char*argv[])
    {
    ? brk(0x09050000);
    ? printf("brk=%p\n",sbrk(0));
    ? char *ptr=malloc(1024);
    ? printf("new=%p\n",ptr);
    ? return 1;
    }
    結果:
  • [root@localhost demo]# ./t
    brk=0x9050000
    new=0x9050010
  • 系統執行一個過程,到底怎么來加載這些空間的?可以用strace工具來查看。
  • ?strace ./t
    execve("./t", ["./t"], [/* 25 vars */]) = 0
    brk(0) ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?= 0x7e0000//起始地址
    mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fb578bba000
    access("/etc/ld.so.preload", R_OK) ? ? ?= -1 ENOENT (No such file or directory)
    open("/etc/ld.so.cache", O_RDONLY) ? ? ?= 3
    fstat(3, {st_mode=S_IFREG|0644, st_size=52315, ...}) = 0
    mmap(NULL, 52315, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7fb578bad000
    close(3) ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?= 0
    open("/lib64/libc.so.6", O_RDONLY) ? ? ?= 3
    read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0000\356A\3012\0\0\0"..., 832) = 832
    fstat(3, {st_mode=S_IFREG|0755, st_size=1926800, ...}) = 0
    mmap(0x32c1400000, 3750152, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x32c1400000
    mprotect(0x32c158b000, 2093056, PROT_NONE) = 0
    mmap(0x32c178a000, 20480, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x18a000) = 0x32c178a000
    mmap(0x32c178f000, 18696, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x32c178f000
    close(3) ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?= 0
    mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fb578bac000
    mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fb578bab000
    mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fb578baa000
    arch_prctl(ARCH_SET_FS, 0x7fb578bab700) = 0
    mprotect(0x32c178a000, 16384, PROT_READ) = 0
    mprotect(0x32c0e1f000, 4096, PROT_READ) = 0
    munmap(0x7fb578bad000, 52315) ? ? ? ? ? = 0
    brk(0x9050000) ? ? ? ? ? ? ? ? ? ? ? ? ?= 0x9050000
    fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 2), ...}) = 0
    mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fb578bb9000
    write(1, "brk=0x9050000\n", 14brk=0x9050000
    ) ? ? ? ? = 14
    brk(0x9071000) ? ? ? ? ? ? ? ? ? ? ? ? ?= 0x9071000
    write(1, "new=0x9050010\n", 14new=0x9050010
    ) ? ? ? ? = 14
    exit_group(1) ? ? ? ? ? ? ? ? ? ? ? ? ? = ?
  • 堆空間的起始地址是隨機的,可設置為不隨機。大小也可以設置成固定大小
    代碼段,數據段,BSS段的地址在編譯鏈接時固定
    在BSS結束和堆起始地址有空隙,這個空隙是隨機的
    brk函數僅僅是調整在堆中申請空間的起始值。使用以下命令可以指定堆的起始地址固定
    sudo sysctl -w kernel/randomize_va_space=0


  • 系統默認為每個進程分配的堆空間大小是固定的。使用 sbrk(0)得到的是我們堆空間的結束
    值。第一次使用 malloc 申請資源返回的地址接近于堆空間的起始值。全用 brk(addr)改變的是新申請數據
    的堆空間起始值。
  • 在真正編程中,很少全用 brk/sbrk,使用 malloc函數來新申請堆空間,效率更高。部分時間使
    用 mmap來映射 mmap區,
    棧:棧從高地址向低地址增長,棧的起始值也是隨機的。棧中主要存放的是局部變量,新調用子函
    數時函數的參數及返回值。由 OS自動管理。

1.3內存空間的申請和釋放
  • 代碼段中:由只讀數據和代碼組成: const,字符串常量,這些內容的空間在編譯鏈接時申請好
    且指定存儲地址。
    ?
  • 數據段 BSS 段申請:定義的全局的或者是靜態的變量。已經初始化的在數據段,未初始化的
    BSS段中。因此也是在編譯鏈接時已經申請且指定的地址。
    以上空間的申請在運行時候就加載到內存中,直到程序的結束,不在發生變化,除了exec函數執行
  • 堆:由程序員自己動態管理。
    動態申請,堆的起始位置由brk函數指定,但是具體編程中一般不會自己使用它,而是使用malloc函數。內核對內存的管理是頁式管理,因此在 malloc申請空間時,使用鏈式結構來管理已經
    申請的堆空間。

  • 棧:由os管理
  • mmap的庫以及相關文件
    將一個文件的內容全部或者部分的映射到虛擬地址空間中,后面釋放時操作這段內存空間可以被同
    步到磁盤文件的操作,效率比較高。共享映射,其它進程如果也映射這個文件,可以立即看到這個更改,但并不是立即更新磁盤文件的內容,如果要更新到磁盤,必須使用 msync以及 munmap時。?

2.常見內存錯誤以及valgrind使用

? ? ? ? ?代碼段:只讀數據。因此對這一部分的數據,試圖寫只讀數據。這個在編譯的時候基本可以檢測。

數據段/BSS段:未初始化直接訪問。即使沒有顯式初始化,仍然會初始化為 0。
棧空間數據:
(1)局部變量,未初始化這類變量會給隨機的初值,出現異常情況更詭異。
(2) 棧溢出,在棧中申請過大的局部變量。
堆空間數據:
內存泄漏,( 1)申請未釋放( 2)申請后,雙重釋放。
對于所有的地址空間:
( 1)野指針的問題。未初始化指針。去訪問這個指針指向的空間。
( 2)越界訪問,例如一個數組 a[10],試圖訪問 a[10]以及以后。
( 3)非法的越權訪問。例如 mmap的空間只讀,但試圖寫。
( 4)空間不在控制范圍仍然去訪問空間,例如返回局部變量地址,且后面訪問這個空間。
使用工具,來檢測常見的內存錯誤。 valgrind工具。
1041 gcc -o valgrind_example01 valgrind_example01.c -g
1042 valgrind --tool=memcheck --show-reachable=yes --read-var-info=yes --verbose --time-stamp=yes --
leak-check=full --log-file=mycode.log ./valgrind_example01
1043 less mycode.log
如果要使用圖形化的工具,要安裝 QT,這個工具名字叫 valkyrie。
? ? ? ? ?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/385261.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/385261.shtml
英文地址,請注明出處:http://en.pswp.cn/news/385261.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

epoll

開發高性能網絡程序時&#xff0c;windows開發者們言必稱iocp&#xff0c;linux開發者們則言必稱epoll。大家都明白epoll是一種IO多路復用技術&#xff0c;可以非常高效的處理數以百萬計的socket句柄&#xff0c;比起以前的select和poll效率高大發了。我們用起epoll來都感覺挺爽…

劍指offer目錄

序號題目1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21

基于升序鏈表的定時器

#ifndef LST_TIMER#define LST_TIMER#include <time.h>#define BUFFER_SIZE 64class util_timer;//用戶數據結構&#xff1a;客戶端地址、客戶端的socket、socket文件描述符、讀緩存和定時器struct client_data{sockaddr_in address;int sockfd;char buf[ BUFFER_SIZE ];…

SIGCHLD信號使用和注意事項

1.SIGCHLD簡介 SIGCHILD是指在一個進程終止或者停止時&#xff0c;將SIGCHILD信號發送給其父進程&#xff0c;按照系統默認將忽略此信號&#xff0c;如果父進程希望被告知其子系統的這種狀態&#xff0c;則應捕捉此信號。注意&#xff1a;SIGCLD信號與其長得非常相似。SIGCLD是…

08-圖7 公路村村通 (30 分

現有村落間道路的統計數據表中&#xff0c;列出了有可能建設成標準公路的若干條道路的成本&#xff0c;求使每個村落都有公路連通所需要的最低成本。 輸入格式: 輸入數據包括城鎮數目正整數N&#xff08;≤&#xff09;和候選道路數目M&#xff08;≤&#xff09;&#xff1b;隨…

【Leetcode】33. 搜索旋轉排序數組

假設按照升序排序的數組在預先未知的某個點上進行了旋轉。 ( 例如&#xff0c;數組 [0,1,2,4,5,6,7] 可能變為 [4,5,6,7,0,1,2] )。 搜索一個給定的目標值&#xff0c;如果數組中存在這個目標值&#xff0c;則返回它的索引&#xff0c;否則返回 -1 。 你可以假設數組中不存在重…

08-圖9 關鍵活動 (30 分

假定一個工程項目由一組子任務構成&#xff0c;子任務之間有的可以并行執行&#xff0c;有的必須在完成了其它一些子任務后才能執行。“任務調度”包括一組子任務、以及每個子任務可以執行所依賴的子任務集。 比如完成一個專業的所有課程學習和畢業設計可以看成一個本科生要完成…

【Leetocde | 10 】54. 螺旋矩陣

解題代碼&#xff1a; class Solution { public:vector<int> spiralOrder(vector<vector<int>>& matrix) {if (matrix.empty() || matrix[0].empty()) return {};int m matrix.size(), n matrix[0].size();vector<int> res;int up 0, down m …

09-排序1 排序 (25 分)

給定N個&#xff08;長整型范圍內的&#xff09;整數&#xff0c;要求輸出從小到大排序后的結果。 本題旨在測試各種不同的排序算法在各種數據情況下的表現。各組測試數據特點如下&#xff1a; 數據1&#xff1a;只有1個元素&#xff1b; 數據2&#xff1a;11個不相同的整數…

網絡層

1. 簡單解釋一些ARP協議的工作過程

【Leetocde | 24 】152. 乘積最大子序列

這道題最直接的方法就是用DP來做&#xff0c;而且要用兩個dp數組&#xff0c;其中f[i]表示子數組[0, i]范圍內并且一定包含nums[i]數字的最大子數組乘積&#xff0c;g[i]表示子數組[0, i]范圍內并且一定包含nums[i]數字的最小子數組乘積&#xff0c;初始化時f[0]和g[0]都初始化…

【Leetcode | 1】3. 無重復字符的最長子串

這里我們可以建立一個HashMap&#xff0c;建立每個字符和其最后出現位置之間的映射&#xff0c;然后我們需要定義兩個變量res和left&#xff0c;其中res用來記錄最長無重復子串的長度&#xff0c;left指向該無重復子串左邊的起始位置的前一個&#xff0c;由于是前一個&#xff…

【Leetcode | 】93. 復原IP地址

class Solution { public:vector<string> strs;//用于存放臨時的四個段vector<string> result;//存放結果void dfs(string &s, int beginIndex, int step) {if (step 4 && beginIndex s.size()) //搜索成功{string temRec strs[0] "." …

海量數據(一)

1. 有1億個浮點數&#xff0c;如果找出期中最大的10000個&#xff1f; 最容易想到的方法是將數據全部排序&#xff0c;然后在排序后的集合中進行查找&#xff0c;最快的排序算法的時間復雜度一般為O&#xff08;nlogn&#xff09;&#xff0c;如快速排序。但是在32位的機器上&a…

1018 錘子剪刀布 (20 分)

大家應該都會玩“錘子剪刀布”的游戲&#xff1a;兩人同時給出手勢&#xff0c;勝負規則如圖所示&#xff1a; 現給出兩人的交鋒記錄&#xff0c;請統計雙方的勝、平、負次數&#xff0c;并且給出雙方分別出什么手勢的勝算最大。 輸入格式&#xff1a; 輸入第 1 行給出正整數 N…

1019 數字黑洞 (20 分)

給定任一個各位數字不完全相同的 4 位正整數&#xff0c;如果我們先把 4 個數字按非遞增排序&#xff0c;再按非遞減排序&#xff0c;然后用第 1 個數字減第 2 個數字&#xff0c;將得到一個新的數字。一直重復這樣做&#xff0c;我們很快會停在有“數字黑洞”之稱的 6174&…

61. 旋轉鏈表

給定一個鏈表&#xff0c;旋轉鏈表&#xff0c;將鏈表每個節點向右移動 k 個位置&#xff0c;其中 k 是非負數。 示例 1: 輸入: 1->2->3->4->5->NULL, k 2 輸出: 4->5->1->2->3->NULL 解釋: 向右旋轉 1 步: 5->1->2->3->4->NULL…

1020 月餅 (25 分)

月餅是中國人在中秋佳節時吃的一種傳統食品&#xff0c;不同地區有許多不同風味的月餅。現給定所有種類月餅的庫存量、總售價、以及市場的最大需求量&#xff0c;請你計算可以獲得的最大收益是多少。 注意&#xff1a;銷售時允許取出一部分庫存。樣例給出的情形是這樣的&#x…

2. 二叉樹的深度

題目描述 輸入一棵二叉樹&#xff0c;求該樹的深度。從根結點到葉結點依次經過的結點&#xff08;含根、葉結點&#xff09;形成樹的一條路徑&#xff0c;最長路徑的長度為樹的深度。 /* struct TreeNode {int val;struct TreeNode *left;struct TreeNode *right;TreeNode(in…

1021 個位數統計 (15 分

給定一個 k 位整數 1 (0, ,, d?k?1??>0)&#xff0c;請編寫程序統計每種不同的個位數字出現的次數。例如&#xff1a;給定 0&#xff0c;則有 2 個 0&#xff0c;3 個 1&#xff0c;和 1 個 3。 輸入格式&#xff1a; 每個輸入包含 1 個測試用例&#xff0c;即一個不超過…