【C++】C\C++内存管理

简介: 【C++】C\C++内存管理

下面是围绕C\C++内存管理这一块知识谈论相关的内存管理机制,有需要借鉴即可。


同时,我在下面也放了快速建立链表的模板,方便oj题目拿到vs上进行调试。

在介绍本节博客之前,请思考为什么要进行内存划分?或者说内存为什么要划分为不同的区域?直接一整块使用多好。

答案是为了方便内存管理。这就类似于我们为什么要对全国进行划分不同给的省份?正是因为划分了不同的省份可以方便管理才这样做的。


1.CPP内存管理

针对于C/CPP语言,我们一般将内存划分为如下几个不同的区域:

注:语言层面名称:静态区、常量区

操作系统层面名称:数据段、代码段

请回答下面代码中的变量分别存储在计算机内存的哪个区域?

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

下面是答案:

对于上面所介绍的这些内存空间,我们作为编写代码的人应该重点关注哪一块区域呢?

答:

是堆空间,因为堆是系统把一部分操作权限给到我们编写代码的人的,包括一些堆的空间申请,堆的空间释放…

在C语言中,我们常用malloc\realloc\calloc进行对堆空间的申请和free释放

因而想要使用堆空间,下面代码基本说是"必经之路"。

思考:malloc、realloc、calloc的区别?

答:

malloc:申请一块空间

realloc:更改空间大小,支持原地扩容和异地扩容

calloc:申请一块空间并初始化

void Test ()
{
int* p1 = (int*) malloc(sizeof(int));
free(p1);
// 1.malloc/calloc/realloc的区别是什么?
int* p2 = (int*)calloc(4, sizeof (int));
int* p3 = (int*)realloc(p2, sizeof(int)*10);
// 这里需要free(p2)吗?
free(p3 );
}

我们申请一块空间是需要先把地址放到一个指针变量里,然后再进行检查…程序复杂且重复。

CPP为了解决这个问题,通过对malloc函数进行封装加工处理,形成了new关键字,通过对free函数的封装加工处理,形成了delete关键字。

1.1new、delete关键字概念

CPP提供的new与delete相对于C语言中的malloc与free的提升主要集中在两个方面,一是用法更加简单,二是功能更加强大

1.2特性

  • 1.用法上,更加简单
  • new关键字替代了malloc(sizeof())和检查那一大堆
  • 2.功能上,更加强大
  • ①开始:可以支持在开辟空间时候初始化

  • ②创建过程:可以支持自定义类型的空间开辟,new自动调用构造函数,delete自动调用对应的析构函数(重点)

  • ③结束:new失败了会抛异常,不用指针检查是否为空

1.3总结

从上面看来,new和delete的语法引入大大方便了我们对堆空间的使用。那其底层是如何实现的呢?

2.new、delete的底层

2.1new的底层是operator new:

new —>operator new + n次构造函数(自定义类型) —>malloc
new[] —> operator new[] —> operator new + n次构造函数(自定义类型) —> malloc

我们以下面代码为例,看其汇编解析其底层:

思考:为什么要定义operator new对malloc实现封装?

答:

①要实现new失败要抛异常

②要调用自定义类型的构造函数


思考:直接new空间,编译器是怎么确定要开多大空间的?C语言中我们需要给空间大小的。

答:通过sizeof编译时进行计算,sizeof是一种运算符,其在编译期间确定,而不是在运行时。


思考:为什么上面自定义类型开空间多开8个字节的空间?

答:主要是多开几个字节的空间来存储这块空间多大,方便下一步delete释放时候要释放多少空间。

注:下图蓝色区域是新开空间存储相关内容的空间区域,红色则是存储这块空间是多大的,方便delete的删除操作。

2.2delete的底层是operator delete

delete —> 析构函数 + operator delete —> free

注意:有些delete[]会进一步调用operator delete

思考:operatr delete是先调用析构函数还是先调用free?

答:先调用析构函数

创建与销毁一定要对等使用,即:

  • 开辟空间:new[] ,释放空间:delete[]
  • 开辟空间:new,释放空间:delete

思考:为什么?

2.3总结

3.内存泄漏

3.1概念

是指一块内存空间申请了不用却也不还给系统。

共分为两种情况:

  • 1.堆内存泄露
    堆内存指的是程序执行中依据须要分配通过malloc / calloc / realloc / new等从堆中分配的一块内存,用完后必须通过调用相应的 free或者delete 删掉。假设程序的设计错误导致这部分内存没有被释放,那么以后这部分空间将无法再被使用,就会产生Heap Leak。
  • 2.系统资源泄露
    指程序使用系统分配的资源,比方套接字、文件描述符、管道等没有使用对应的函数释放掉,导致系统资源的浪费,严重可导致系统效能减少,系统执行不稳定。

4.快速生成链表模板

#include<iostream>
using namespace std;
struct ListNode
{
  int _val;
  ListNode* _next;
  //构造函数初始化
  ListNode(int val = 0)
    :_val(val)
    , _next(nullptr)
  {}
};
ListNode* CreatList(int n)
{
  ListNode head(-1);//生成一个类对象
  ListNode* tail = &head;//尾指针
  int val;
  printf("请依次输入%d个节点的val值:>\n", n);
  for (int i = 0; i < n; i++)
  {
    //cin >> val;
    val = i;
    tail->_next = new ListNode(val);
    tail = tail->_next;
  }
  return head._next;
}
void test2()
{
  ListNode* head = CreatList(100);
  ListNode* pcur = head;
  for (int i = 0; i < 100; i++)
  {
    cout << pcur->_val << "  ";
    pcur = pcur->_next;
  }
}

EOF

相关文章
|
4月前
|
安全 C语言 C++
比较C++的内存分配与管理方式new/delete与C语言中的malloc/realloc/calloc/free。
在实用性方面,C++的内存管理方式提供了面向对象的特性,它是处理构造和析构、需要类型安全和异常处理的首选方案。而C语言的内存管理函数适用于简单的内存分配,例如分配原始内存块或复杂性较低的数据结构,没有构造和析构的要求。当从C迁移到C++,或在C++中使用C代码时,了解两种内存管理方式的差异非常重要。
149 26
|
9月前
|
存储 程序员 编译器
玩转C++内存管理:从新手到高手的必备指南
C++中的内存管理是编写高效、可靠程序的关键所在。C++不仅继承了C语言的内存管理方式,还增加了面向对象的内存分配机制,使得内存管理既有灵活性,也更加复杂。学习内存管理不仅有助于提升程序效率,还有助于理解计算机的工作原理和资源分配策略。
|
5月前
|
C语言 C++
c与c++的内存管理
再比如还有这样的分组: 这种分组是最正确的给出内存四个分区名字:栈区、堆区、全局区(俗话也叫静态变量区)、代码区(也叫代码段)(代码段又分很多种,比如常量区)当然也会看到别的定义如:两者都正确,记那个都选,我选择的是第一个。再比如还有这样的分组: 这种分组是最正确的答案分别是 C C C A A A A A D A B。
77 1
|
11月前
|
存储 缓存 编译器
【硬核】C++11并发:内存模型和原子类型
本文从C++11并发编程中的关键概念——内存模型与原子类型入手,结合详尽的代码示例,抽丝剥茧地介绍了如何实现无锁化并发的性能优化。
441 68
|
8月前
|
存储 Linux C语言
C++/C的内存管理
本文主要讲解C++/C中的程序区域划分与内存管理方式。首先介绍程序区域,包括栈(存储局部变量等,向下增长)、堆(动态内存分配,向上分配)、数据段(存储静态和全局变量)及代码段(存放可执行代码)。接着探讨C++内存管理,new/delete操作符相比C语言的malloc/free更强大,支持对象构造与析构。还深入解析了new/delete的实现原理、定位new表达式以及二者与malloc/free的区别。最后附上一句鸡汤激励大家行动缓解焦虑。
|
9月前
|
安全 C语言 C++
彻底摘明白 C++ 的动态内存分配原理
大家好,我是V哥。C++的动态内存分配允许程序在运行时请求和释放内存,主要通过`new`/`delete`(用于对象)及`malloc`/`calloc`/`realloc`/`free`(继承自C语言)实现。`new`分配并初始化对象内存,`delete`释放并调用析构函数;而`malloc`等函数仅处理裸内存,不涉及构造与析构。掌握这些可有效管理内存,避免泄漏和悬空指针问题。智能指针如`std::unique_ptr`和`std::shared_ptr`能自动管理内存,确保异常安全。关注威哥爱编程,了解更多全栈开发技巧。 先赞再看后评论,腰缠万贯财进门。
402 0
|
10月前
|
存储 程序员 编译器
什么是内存泄漏?C++中如何检测和解决?
大家好,我是V哥。内存泄露是编程中的常见问题,可能导致程序崩溃。特别是在金三银四跳槽季,面试官常问此问题。本文将探讨内存泄露的定义、危害、检测方法及解决策略,帮助你掌握这一关键知识点。通过学习如何正确管理内存、使用智能指针和RAII原则,避免内存泄露,提升代码健壮性。同时,了解常见的内存泄露场景,如忘记释放内存、异常处理不当等,确保在面试中不被秒杀。最后,预祝大家新的一年工作顺利,涨薪多多!关注威哥爱编程,一起成为更好的程序员。
427 0
|
12月前
|
存储 缓存 C语言
【c++】动态内存管理
本文介绍了C++中动态内存管理的新方式——`new`和`delete`操作符,详细探讨了它们的使用方法及与C语言中`malloc`/`free`的区别。文章首先回顾了C语言中的动态内存管理,接着通过代码实例展示了`new`和`delete`的基本用法,包括对内置类型和自定义类型的动态内存分配与释放。此外,文章还深入解析了`operator new`和`operator delete`的底层实现,以及定位new表达式的应用,最后总结了`malloc`/`free`与`new`/`delete`的主要差异。
198 3
|
12月前
|
存储 编译器 Linux
【c++】类和对象(上)(类的定义格式、访问限定符、类域、类的实例化、对象的内存大小、this指针)
本文介绍了C++中的类和对象,包括类的概念、定义格式、访问限定符、类域、对象的创建及内存大小、以及this指针。通过示例代码详细解释了类的定义、成员函数和成员变量的作用,以及如何使用访问限定符控制成员的访问权限。此外,还讨论了对象的内存分配规则和this指针的使用场景,帮助读者深入理解面向对象编程的核心概念。
574 4
|
程序员 C++ 容器
在 C++中,realloc 函数返回 NULL 时,需要手动释放原来的内存吗?
在 C++ 中,当 realloc 函数返回 NULL 时,表示内存重新分配失败,但原内存块仍然有效,因此需要手动释放原来的内存,以避免内存泄漏。