内存管理(从底层到高层):
硬件层次
内存结构管理
内核层次
内存映射
堆扩展
语言层次
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.决定了函数的名字转换方式。