内存结构-堆结构-内存分配函数

来源:互联网 发布:同程网络 编辑:程序博客网 时间:2024/03/28 20:16

内存管理(从底层到高层):

硬件层次

内存结构管理

内核层次

内存映射

堆扩展

语言层次 

c::malloc    

c++:new

数据结构

STL(Standard Template Library,标准模板库

智能指针


例1

运行:编辑malloc.c

#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);}


执行:gcc malloc.c -o malloc
结果:

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:


目录/proc/${pid}/ 存放进程运行时候所有的信息包括内存结构
exe 指向当前运行的程序
cwd 连接 指向当前程序所在目录
maps 保存程序运行的所有的内存结构


编辑:

#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);}



cd  /proc/    
ps aue

运行结果:
a1:0x80497e4 //全局变量--------在全局区
a2:0x80497e8 //全局静态变量--在全局区
a3:0x80485f4 //全局常量--------在代码区
b1:0xbfa06c28 //局部变量--------在局部栈
b2:0x80497ec //局部静态变量--在全局区
b3:0xbfa06c24 //局部常量--------在局部栈
p1:0x84c1008 //指针--------------在堆
main:0x8048432 //在代码区
add:0x8048424 //在代码区
4710


查看进程id  进入相应的文件夹   再查看maps
[sh@localhost ~]$ ll /proc/4710/cwd
lrwxrwxrwx. 1 sh SH 0 2月  28 17:53 /proc/4710/cwd -> /home/SH/project/cpp/test

[sh@localhost ~]$ ll /proc/4710/exe
lrwxrwxrwx. 1 sh SH 0 2月  28 17:53 /proc/4710/exe -> /home/SH/project/cpp/test/main

[sh@localhost ~]$ cat /proc/4710/maps

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
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]/栈

4K为1页

结论:
任何程序的内存空间分成4个基本部分
1.代码区
2.全局栈区
3.堆
4.局部栈



堆栈的区别

例3:

编辑statckleap.c
#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);}

结果
0xbf8bfb50|
0xbf8bfb4c |  栈相差4字节
0xbf8bfb48 |
0x8734008 |
0x8734018 |  堆相差10字节
0x8734028 |
3531

查看3531进程:
005a6000-005a7000 r-xp 00000000 00:00 0          [vdso]
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]


结论:

  1. 内存分为4个区。
  2. 各种变量对应存放区。
  3. 堆栈是一种管理内出的数据结构。
  4. 查看一个程序的内存地址。

3.理解malloc工作原理


例4

编辑mallocstruck.c  (越界访问)
#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);}
结果是:
5
0

结论:

malloc使用一个数据结构(链表)来维护我们分配的空间,
连标的构成:分配的空间、上个空间数据、下个空间数据、空间大小等信息
读malloc分配的空间不要越界访问,应为容易破坏后台维护机构,导致 malloc、free、calloc、realloc不正常工作。

4.c++的new与malloc的关系

malloc newnew[]
realloc(定位分配) new()
calloc new[]
free delete、delete[]

new的实现使用malloc来实现的。
区别:new使用malloc后还要初始化空间,
基本类型,直接初始化成默认值,
UDT类型(用户自定义类型:类,结构体),调用指定的构造器

同样,delete是调用free实现。
区别:delete负责调用析构器,然后再调用free。

new 与new[ ]的区别:
new只调用一个构造器初始化。
new[ ]循环对每个区域调用构造器。

delete 月 delete[]的区别:
例子: Stu *p = new Stu[30];
delete p;调用一个析构函数,再把p指向的空间群全部释放。
delete[] p;循环调用每个析构函数,再把p指向的空间群全部释放。

5.函数调用栈空间的分配与释放

5.1 总结

  1. 函数执行的时候有自己的临时栈空间。
  2. 函数的参数就在临时栈中,如果函数传递实参,则用来初始化临时参数变量。
  3. 通过寄存器返回值。(使用返回值返回数据)
  4. 通过参数返回值。(参必须是指针,指针指向的区域必须事先分配)
  5. 如果参数返回指针,参数就是双指针。

5.2 __stdcall  __cdecl  __fastcall

写在函数名前:linux:__attribute__((stdcall))  
 windows:__stdcall
1.决定含糊栈压栈顺序。从右到左
2.决定函数栈清空方式。
3.决定了函数的名字转换方式。

同样,delete是调用free实现。



0 0
原创粉丝点击