【内存分布管理】new与malloc以及delede与delete[]的区别

简介: 【内存分布管理】new与malloc以及delede与delete[]的区别

1.内存分布示意图(重要)

其中数据共享区也叫内存映射段,是高效的I/O映射方式,用于装载一个共享的动态内存库。用户可使用系统接口创建共享共享内存,做进程间通信

2.判断以下程序中的变量在什么区域

int globalVar = 1;
static int staticGlobalVar = 1;
void Test()
{
 static int staticVar = 1;
 int localVar = 1;
 int num1[10] = { 1, 2, 3, 4 };
 char char2[] = "abcd";
 const char* pChar3 = "abcd";
 int* ptr1 = (int*)malloc(sizeof(int) * 4);
 int* ptr2 = (int*)calloc(4, sizeof(int));
 int* ptr3 = (int*)realloc(ptr2, sizeof(int) * 4);
 free(ptr1);
 free(ptr3);
}
  1. 选择题: 选项: A.栈 B.堆 C.数据段(静态区) D.代码段(常量区) globalVar在哪里?C staticGlobalVa在哪里?C staticVar在哪里?_C localVar在哪里?A

     num1 在哪里?A

     char2在哪里?A *char2在哪里?A pChar3在哪里?A *pChar3在哪里?D ptr1在哪里?A *ptr1在 哪里?B

  1. 填空题: sizeof(num1) = 40; (sizezof 数组名等于整个数组的大小) sizeof(char2) = 5__; strlen(char2) = 4; sizeof(pChar3) =

     4; strlen(pChar3) = 4; sizeof(ptr1) = 4;

  1. sizeof 和 strlen 区别? 答:sizeof 计算的是字节的大小,sizezof 数组名等于整个数组的大小,strlen计算字符串的长度,遇到‘\0’为止

3.new和delete

new和delete是C++动态开辟与释放内存互相匹配的的两个操作符,因此不需要头文件。C语言内存管理方式在C++中可以继续使用,但有些地方就无能为力,而且使用起来比较麻烦,因此C++又提出了自己的内存管理方式:通过new和delete操作符进行动态内存管理。

本质上,new的底层也是通过malloc来实现的

new与delete的使用示例

void Test()
{
  // 动态申请一个int类型的空间
  int* ptr4 = new int;
  
  // 动态申请一个int类型的空间并初始化为10
  int* ptr5 = new int(10);
  
  // 动态申请10个int类型的空间
  int* ptr6 = new int[3];
 
  delete ptr4;
  delete ptr5;
  delete[] ptr6;
}

注意:申请和释放单个元素的空间,使用new和delete操作符,申请和释放连续的空间,使用new[]和delete[]使用的时候要互相匹配

4.malloc和new的区别

1.属性:new是关键字,而malloc是函数。

2.参数:new操作符会无需指定内存块的大小,编译器会自己根据类型算,而malloc需要显式的指定。

3.返回值类型:newc操作符申请成功时返回该对象类型的指针,无需强制转换,申请失败的时候会报异常。而malloc函数申请成功返回的时void*类型的指针,大多需要强制类型转换,申请失败会返回一个NULL.

4.new可以调用malloc来实现,但是malloc不可以。

5.对于自定义类型开辟空间

对于内置类型,new与malloc几乎没有什么区别,但是对于自定义类型,也就是class,new和delete会调用构造函数和析构函数.

5.delete和delete[]的区别

delete 释放new分配的单个对象指针指向的内存;
delete[] 释放new分配的对象数组指针指向的内存。

对于内置类型

delete和delete[]的效果是一样的

void test2() {
  int* a = new int[4];
  int* b = new int;
  delete[] a;
  delete b;
}

因为对于内置类型,在new分配内存的时候就已经确定了内存的大小,并且记录了下来, 系统可以记忆并且进行管理,在析构时,系统并不会调用析构函数

对于自定义类型:

void test3() {
  A* p1 = new A[5];
  //delete p1;错误
  delete[] p1;
}

delete与delete[]的效果是不一样的,delete只会调用一次析构函数,而delete[]会调用多次。那么delete[]是如何知道需要调用多少次析构函数呢?也就是如何知道对象数组的元素个数呢?如果我们开辟了用new []开辟了对象数组,编译器会在数组的前面再开辟一块空间用来存放元素个数。

此时如果用delete[]释放空间,它会先从上一块区域(32位系统是4字节,64位是8个字节)读取元素个数并释放

这也是为什么用delete 释放对象数组会报错误,因为deletet是从指针p1指向的位置开始,但是实际上p1上一面的内存块也要释放。动态内存不能只释放一部分

5.内存泄漏

内存泄漏指因为疏忽或错误造成程序未能释放已经不再使用的内存的情况。内存泄漏并不是指内存在物理上的消失,而是应用程序分配某段内存后,因为设计错误失去了对该段内存的控制,因而造成了内存的浪费。

内存泄漏的危害:长期运行的程序出现内存泄漏,影响很大,如操作系统、后台服务等等,出现内存泄漏会导致响应越来越慢,最终卡死。

内存泄漏的分类:

堆内存泄漏(heap leak):

堆内存泄漏是指程序中通过new/malloc等申请到的堆空间没有及时用delete/free释放掉,导致这片空间无法再被申请。

系统内存泄漏

指程序使用系统分配的资源,比方套接字、文件描述符、管道等没有使用对应的函数释放掉,导致系统资源的浪费,严重可导致系统效能减少,系统执行不稳定。

_CrtDumpMemoryLeaks() 函数

crtdbg模块的c++_CrtDumpMemoryLeaks函数可以检测C、C++代码中的内存泄漏错误。在需要检测的代码前后分别调用_CrtDumpMemoryLeaks函数,就可以看到该代码片段是否发送内存泄漏,以及泄露的空间大小,但是不能提供泄漏的具体地址。注意,要在进入调试窗口才能看到该信息。

如何避免内存泄漏

  1. 工程前期良好的设计规范,养成良好的编码规范,申请的内存空间记着匹配的去释放。
  2. 采用RAII思想或者智能指针来管理资源。
  3. 有些公司内部规范使用内部实现的私有内存管理库。这套库自带内存泄漏检测的功能选项。
  4. 使用内存泄漏工具检测。
    总结:

1、事前预防型。如智能指针等。2、事后查错型。如泄漏检测工具。

相关文章
|
28天前
|
C++
【C++】深入解析C/C++内存管理:new与delete的使用及原理(二)
【C++】深入解析C/C++内存管理:new与delete的使用及原理
|
28天前
|
编译器 C++ 开发者
【C++】深入解析C/C++内存管理:new与delete的使用及原理(三)
【C++】深入解析C/C++内存管理:new与delete的使用及原理
|
28天前
|
存储 C语言 C++
【C++】深入解析C/C++内存管理:new与delete的使用及原理(一)
【C++】深入解析C/C++内存管理:new与delete的使用及原理
|
26天前
|
程序员 C语言 C++
C++入门5——C/C++动态内存管理(new与delete)
C++入门5——C/C++动态内存管理(new与delete)
53 1
|
26天前
|
编译器 C语言 C++
详解C/C++动态内存函数(malloc、free、calloc、realloc)
详解C/C++动态内存函数(malloc、free、calloc、realloc)
98 1
|
22天前
一刻也没有为它哀悼~接下来登场的是动态内存分配的malloc与realloc以及free函数
一刻也没有为它哀悼~接下来登场的是动态内存分配的malloc与realloc以及free函数
55 0
|
3月前
|
存储 编译器 C语言
【C语言篇】数据在内存中的存储(超详细)
浮点数就采⽤下⾯的规则表⽰,即指数E的真实值加上127(或1023),再将有效数字M去掉整数部分的1。
298 0
|
5天前
|
存储 C语言
数据在内存中的存储方式
本文介绍了计算机中整数和浮点数的存储方式,包括整数的原码、反码、补码,以及浮点数的IEEE754标准存储格式。同时,探讨了大小端字节序的概念及其判断方法,通过实例代码展示了这些概念的实际应用。
13 1
|
10天前
|
存储
共用体在内存中如何存储数据
共用体(Union)在内存中为所有成员分配同一段内存空间,大小等于最大成员所需的空间。这意味着所有成员共享同一块内存,但同一时间只能存储其中一个成员的数据,无法同时保存多个成员的值。
|
14天前
|
存储 弹性计算 算法
前端大模型应用笔记(四):如何在资源受限例如1核和1G内存的端侧或ECS上运行一个合适的向量存储库及如何优化
本文探讨了在资源受限的嵌入式设备(如1核处理器和1GB内存)上实现高效向量存储和检索的方法,旨在支持端侧大模型应用。文章分析了Annoy、HNSWLib、NMSLib、FLANN、VP-Trees和Lshbox等向量存储库的特点与适用场景,推荐Annoy作为多数情况下的首选方案,并提出了数据预处理、索引优化、查询优化等策略以提升性能。通过这些方法,即使在资源受限的环境中也能实现高效的向量检索。