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

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

硬件层次

内存结构管理

内核层次

内存映射

堆扩展

语言层次 

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 new new[]
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实现。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值