內存管理(從底層到高層):
硬件層次
內存結構管理
內核層次
內存映射
堆擴展
語言層次
c::malloc
c++:new
數據結構
STL(Standard Template Library,標準模板庫)
智能指針
例1
運行:編輯malloc.c
執行:gcc malloc.c -o malloc#include <stdio.h> #include <stdlib.h> main() { int *p1=malloc(4); int *p2=malloc(4); int *p3=malloc(4); int *p4=malloc(4); int *p5=malloc(4); printf("%p\n",p1); printf("%p\n",p2); printf("%p\n",p3); printf("%p\n",p4); printf("%p\n",p5); }
結果:
0x9066008
0x9066018
0x9066028
0x9066038
0x9066048
問題是:爲什麼開闢4字節空間,而實際上是開闢的空間間距是16字節?
嘗試使用標準c++來寫
#include <stdio.h>
#include <stdlib.h>
int main()
{
int *p1=new int;
int *p2=new int;
int *p3=new int;
int *p4=new int;
int *p5=new int;
printf("%p\n",p1);
printf("%p\n",p2);
printf("%p\n",p3);
printf("%p\n",p4);
printf("%p\n",p5);
return 0;
}
執行:g++ malloc.cpp -o new
結果:
0x8b53008
0x8b53018
0x8b53028
0x8b53038
0x8b53048
對比,和c的結果一模一樣。
1.問題:malloc怎麼分配空間?malloc月new的關係?
2.Linux對內存的結構描述
例2:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int add(int a,int b)
{
return a+b;
}
//全局區
int a1 = 1; //全局變量
static int a2=2;//全局靜態變量
const int a3=3; //全局常量
main()
{
int b1=4;
static b2=5;
const b3 =6;
int *p1=malloc(4);
printf("a1:%p\n",&a1);
printf("a2:%p\n",&a2);
printf("a3:%p\n",&a3);
printf("b1:%p\n",&b1);
printf("b2:%p\n",&b2);
printf("b3:%p\n",&b3);
printf("p1:%p\n",p1);
printf("main:%p\n",&main);
printf("add:%p\n",&add);
printf("%d\n",getpid());
while (1);
}
a2:0x80497e8 //全局靜態變量--在全局區
b1:0xbfa06c28 //局部變量--------在局部棧
b2:0x80497ec //局部靜態變量--在全局區
b3:0xbfa06c24 //局部常量--------在局部棧
p1:0x84c1008 //指針--------------在堆
main:0x8048432 //在代碼區
add:0x8048424 //在代碼區
4710
[sh@localhost ~]$ ll /proc/4710/cwd
[sh@localhost ~]$ ll /proc/4710/exe
[sh@localhost ~]$ cat /proc/4710/maps
007ed000-007ee000 r--p 0001d000 fd:00 26990 /lib/ld-2.12.so
007ee000-007ef000 rw-p 0001e000 fd:00 26990 /lib/ld-2.12.so
007f9000-007fa000 r-xp 00000000 00:00 0 [vdso]
00832000-009c3000 r-xp 00000000 fd:00 26991 /lib/libc-2.12.so
009c3000-009c5000 r--p 00191000 fd:00 26991 /lib/libc-2.12.so
009c5000-009c6000 rw-p 00193000 fd:00 26991 /lib/libc-2.12.so
009c6000-009c9000 rw-p 00000000 00:00 0
08048000-08049000 r-xp 00000000 fd:00 17633 /home/SH/project/cpp/test/main 代碼區,x可執行
08049000-0804a000 rw-p 00000000 fd:00 17633 /home/SH/project/cpp/test/main 全局區
084c1000-084e2000 rw-p 00000000 00:00 0 [heap]/堆
b7731000-b7732000 rw-p 00000000 00:00 0
b7743000-b7745000 rw-p 00000000 00:00 0
bf9f3000-bfa08000 rw-p 00000000 00:00 0 [stack]/棧
例3:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
main()
{
int a1=10;
int a2=20;
int a3=30;
int *p1=malloc(4);
int *p2=malloc(4);
int *p3=malloc(4);
printf("%p\n",&a1);
printf("%p\n",&a2);
printf("%p\n",&a3);
printf("%p\n",p1);
printf("%p\n",p2);
printf("%p\n",p3);
printf("%d\n",getpid());
while(1);
}
結果
0xbf8bfb4c | 棧相差4字節
0xbf8bfb48 |
0x8734008 |
0x8734018 | 堆相差10字節
0x8734028 |
3531
007cf000-007ed000 r-xp 00000000 fd:00 26990 /lib/ld-2.12.so
007ed000-007ee000 r--p 0001d000 fd:00 26990 /lib/ld-2.12.so
007ee000-007ef000 rw-p 0001e000 fd:00 26990 /lib/ld-2.12.so
00832000-009c3000 r-xp 00000000 fd:00 26991 /lib/libc-2.12.so
009c3000-009c5000 r--p 00191000 fd:00 26991 /lib/libc-2.12.so
009c5000-009c6000 rw-p 00193000 fd:00 26991 /lib/libc-2.12.so
009c6000-009c9000 rw-p 00000000 00:00 0
08048000-08049000 r-xp 00000000 fd:00 17633 /home/SH/project/cpp/test/main
08049000-0804a000 rw-p 00000000 fd:00 17633 /home/SH/project/cpp/test/main
08734000-08755000 rw-p 00000000 00:00 0 [heap]
b774e000-b774f000 rw-p 00000000 00:00 0
b7760000-b7762000 rw-p 00000000 00:00 0
bf8ad000-bf8c2000 rw-p 00000000 00:00 0 [stack]
結論:
- 內存分爲4個區。
- 各種變量對應存放區。
- 堆棧是一種管理內出的數據結構。
- 查看一個程序的內存地址。
3.理解malloc工作原理
例4
#include <stdio.h>
#include <stdlib.h>
main()
{
int *p1=malloc(4);
int *p2=malloc(4);
int *p3=malloc(4);
*p1=1;
*(p1+1)=2;
*(p1+2)=3;
*(p1+3)=4;
*(p1+4)=5;
*(p1+5)=6;
printf("%d\n",*p2);
printf("%d\n",*p3);
}
結果是:0
結論:
4.c++的new與malloc的關係
區別:new使用malloc後還要初始化空間,
基本類型,直接初始化成默認值,
UDT類型(用戶自定義類型:類,結構體),調用指定的構造器
區別:delete負責調用析構器,然後再調用free。
new只調用一個構造器初始化。
new[ ]循環對每個區域調用構造器。
例子: Stu *p = new Stu[30];
delete p;調用一個析構函數,再把p指向的空間羣全部釋放。delete[] p;循環調用每個析構函數,再把p指向的空間羣全部釋放。
5.函數調用棧空間的分配與釋放
5.1 總結
- 函數執行的時候有自己的臨時棧空間。
- 函數的參數就在臨時棧中,如果函數傳遞實參,則用來初始化臨時參數變量。
- 通過寄存器返回值。(使用返回值返回數據)
- 通過參數返回值。(參必須是指針,指針指向的區域必須事先分配)
- 如果參數返回指針,參數就是雙指針。
5.2 __stdcall __cdecl __fastcall
1.決定含糊棧壓棧順序。從右到左2.決定函數棧清空方式。3.決定了函數的名字轉換方式。