malloc的分配方法

转自http://blog.youkuaiyun.com/shawvichan/article/details/17680435

1 linux 对内存的结构描述

/proc/${pid}/ 存放进程运行时候的所有信息(包括内存结构)
ps aue 查看pid
进入这个目录

cat maps 


由于当进程存在时那个pid文件夹才存在,所以你需要写一个死循环保证程序一直在运行

[cpp]  view plain copy
  1. #include <unistd.h>  
  2. #include <stdio.h>  
  3. int main()  
  4. {  
  5.     printf("%d\n",getpid());  
  6.     while(1){}  
  7. }  


2.理解malloc的工作的原理

malloc实际上使用一个数据结构(链表)维护分配的空间,
链表的构成: 分配的空间(n)/上一个空间指针(4)/下一个空间指针(4)/空间大小(4)
计算占用空间大小要采用对齐
对malloc分配的空间不要越界访问,因为容易破坏后台维护结构

导致malloc/free/callo/realloc不正常工作

这就是为什么连续使用 malloc 分配的首地址 之间的间隔不等于分配的空间大小的原因.

这就是为什么动态分配的空间, 越界修改后,会导致malloc/free/callo/realloc不正常工作的原因,


示例: 发现每个地址之间相差16. new的情况和这样一样

[cpp]  view plain copy
  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3.   
  4. int main()  
  5. {  
  6.     int *p1 = (int *)malloc(4);  
  7.     int *p2 = (int *)malloc(8);  
  8.     int *p3 = (int *)malloc(16);  
  9.     int *p4 = (int *)malloc(8);  
  10.     int *p5 = (int *)malloc(8);  
  11.     int *p6 = (int *)malloc(4);  
  12.     int *p7 = (int *)malloc(4);  
  13.       
  14.     printf("%p\n",p1); //  %p输出地址,   %x 输出16进制,后面只能是整形  
  15.     printf("%p\n",p2);  
  16.     printf("%p\n",p3);  
  17.     printf("%p\n",p4);  
  18.     printf("%p\n",p5);  
  19.     printf("%p\n",p6);  
  20.     printf("%p\n",p7);  
  21.       
  22.     /* 
  23.     0x881b008 
  24.     0x881b018 
  25.     0x881b028 
  26.     0x881b038 
  27.     0x881b048 
  28.     0x881b058 
  29.     0x881b068 
  30.     */  
  31. }  


示例: 越界赋值后出现错误 

[cpp]  view plain copy
  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <unistd.h>  
  4.   
  5. main()  
  6. {  
  7.     int* p1 =(int*)malloc(4);  
  8.     int* p2 =(int*)malloc(16);  
  9.     int* p3 =(int*)malloc(4);  
  10.       
  11.     *p1 =1;  
  12.     *(p1+1)=2;  
  13.     *(p1+2)=3;  
  14.     *(p1+3)=4;  
  15.     *(p1+4)=5;  
  16.     *(p1+5)=6;  
  17.     *(p1+6)=7;  
  18.     *(p1+7)=8;  
  19.     printf("*p2:%d\n",*p2); //5   
  20.     //free(p1); // 会出严重问题  
  21.     /* 
  22.     堆的结构: 
  23.     1 指向本空间的指针 
  24.     2 指向上一个空间的指针 
  25.     3 指向下一个空间的指针 
  26.     4 本空间的大小 
  27.     */  
  28. }  
这是因为修改了结构体里面的其它部分的值.



3 c++的new 和 malloc的关系
对应关系:
malloc  new new[ ]
realloc  new(void *p)  定位分配  在已有的空间上重新分配
calloc  new[ ]
free  delete delete[]


[cpp]  view plain copy
  1. #include <stdio.h>  
  2.   
  3. #include <new>  
  4.   
  5. int main()  
  6. {  
  7.     int a[20];  
  8.     int *p = new(a) int// 定位分配运算符  
  9.       
  10.       
  11. }  




结论:new的实现使用的是malloc
区别:new使用malloc以后初始化空间
(基本类型:初始化成默认值。自定义类型:调用构造函数)


delete 调用free实现的
delete 先调用析构函数再调用free


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


delete与delete[]的区别:
delete只调用一个构造器析构和释放
delete[] 循环对每个构造器析构和释放
在C语言中,`malloc` 分配内存失败时会返回 `NULL` 指针。若未正确处理这种错误,可能导致程序崩溃或未定义行为。以下是详细说明和最佳实践: --- ### **回答** 1. **`malloc` 失败的原因** - 系统内存不足(物理内存或交换空间耗尽)。 - 请求的内存块过大(超过进程地址空间限制)。 - 内存碎片化严重,无法分配连续内存块。 2. **检查 `malloc` 返回值** 必须检查返回值是否为 `NULL`,避免解引用空指针。 **示例**: ```c int* ptr = (int*)malloc(sizeof(int) * 1000000000000); // 尝试分配极大内存 if (ptr == NULL) { fprintf(stderr, "Memory allocation failed: %s\n", strerror(errno)); exit(EXIT_FAILURE); // 或采取其他错误处理措施 } ``` 3. **错误处理策略** - **终止程序**:若内存是继续运行的必要条件,可打印错误信息并退出。 - **降级处理**:尝试分配更小的内存块或使用备用方案。 - **重试机制**:在延迟后重试(适用于临时性内存不足)。 - **返回错误码**:在库函数中,通过返回值或输出参数通知调用者。 4. **结合 `errno` 和 `perror`** `malloc` 失败时可能设置 `errno`(如 `ENOMEM`),可用 `perror` 或 `strerror` 输出错误详情。 **示例**: ```c #include <errno.h> #include <string.h> void* safeMalloc(size_t size) { void* ptr = malloc(size); if (ptr == NULL) { perror("malloc failed"); // 输出:malloc failed: Cannot allocate memory // 或 fprintf(stderr, "Error: %s\n", strerror(errno)); } return ptr; } ``` 5. **避免常见陷阱** - **未初始化指针**:即使 `malloc` 失败,指针也会被初始化为 `NULL`,但其他逻辑错误(如重复释放)仍需避免。 - **假设分配成功**:切勿跳过错误检查。 - **大数乘法溢出**:计算 `sizeof(type) * n` 时,可能因 `size_t` 溢出导致实际分配内存小于预期。 **错误示例**: ```c size_t n = -1; // 极大值 int* ptr = malloc(sizeof(int) * n); // 乘法溢出,实际分配可能极小 ``` --- ### **关键结论** - **始终检查 `NULL`**:`malloc` 失败时必须处理错误。 - **错误信息友好**:使用 `perror` 或 `strerror` 帮助调试。 - **防御性编程**:处理大数乘法溢出和重复释放等问题。 --- ### **扩展:安全分配函数封装** ```c #include <stdlib.h> #include <stdio.h> #include <errno.h> void* xmalloc(size_t size) { void* ptr = malloc(size); if (ptr == NULL) { fprintf(stderr, "Fatal: Failed to allocate %zu bytes: %s\n", size, strerror(errno)); abort(); // 或 exit(EXIT_FAILURE); } return ptr; } // 使用示例 int main() { int* arr = xmalloc(sizeof(int) * 100); // 分配失败时程序终止 // ... 使用 arr ... free(arr); return 0; } ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值