网站简繁体转换 js,网站开发参数,怎么搭建个人网站电脑做服务器,怎样看网站是什么语言做的CSDN 博客#xff1a;C/C 内存管理详解
在软件开发过程中#xff0c;内存管理是一个非常重要的环节。对于 C 和 C 这两种编程语言#xff0c;它们都拥有独特的内存管理机制#xff0c;理解这些机制对于编写高效、健壮的程序至关重要。本文将详细讲解 C/C 内存管理相关的内…CSDN 博客C/C 内存管理详解
在软件开发过程中内存管理是一个非常重要的环节。对于 C 和 C 这两种编程语言它们都拥有独特的内存管理机制理解这些机制对于编写高效、健壮的程序至关重要。本文将详细讲解 C/C 内存管理相关的内容并重点分析不同内存分配方式的区别和使用场景。
1. C/C 内存分布
在 C 和 C 中内存可以分为多个区域包括栈、堆、数据段、代码段等。这些区域分别用来存储不同类型的数据。通过以下示例代码我们可以直观地理解这些区域的作用
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);
}以下是对应变量在内存中的分布情况
变量名存储位置存储段globalVar全局变量数据段静态区staticGlobalVar静态全局变量数据段静态区staticVar静态局部变量数据段静态区localVar局部变量栈num1局部数组栈char2字符数组栈*char2数组元素存储位置栈pChar3指针变量栈*pChar3常量字符串 “abcd”代码段常量区ptr1指针变量栈*ptr1动态分配内存堆ptr2指针变量栈*ptr2动态分配内存堆ptr3指针变量栈*ptr3动态分配内存堆
内存区域分类
栈Stack存储局部变量如 localVar以及函数调用时的参数和返回值。堆Heap存储动态分配的内存如通过 malloc、calloc、realloc 分配的内存。数据段Data Segment存储全局变量和静态变量如 globalVar 和 staticGlobalVar。代码段Code Segment存储程序的可执行代码以及只读常量如 pChar3 所指向的字符串。
2. C语言中的动态内存管理
C 语言提供了几种用于动态分配内存的函数malloc、calloc、realloc 和 free。这些函数用于在程序运行时动态地分配和释放内存。
2.1 malloc、calloc 和 realloc 的区别
malloc用于分配指定大小的内存块内存中的内容未初始化。calloc类似于 malloc但会将内存初始化为零。它的参数为元素的数量和每个元素的大小。realloc用于调整之前分配的内存块的大小如果新大小大于原大小可能会移动内存块的位置。
示例代码
int* ptr1 (int*)malloc(sizeof(int) * 4); // 分配4个int类型大小的内存块
int* ptr2 (int*)calloc(4, sizeof(int)); // 分配并初始化4个int类型大小的内存块
int* ptr3 (int*)realloc(ptr2, sizeof(int) * 4); // 重新分配内存
free(ptr1);
free(ptr3);2.2 malloc 实现原理
malloc 底层通常通过操作系统的 brk 或 mmap 系统调用分配内存。具体实现可能因平台和 C 标准库的不同而有所区别。在 GNU C 库glibc中malloc 通过维护一个自由链表来跟踪已分配和未分配的内存块并根据请求的大小寻找合适的内存块进行分配。
3. C 内存管理
C 继承了 C 语言的内存管理方式并在此基础上引入了 new 和 delete 操作符提供更方便的动态内存管理机制。与 malloc 和 free 不同new 和 delete 适用于对象的动态内存分配并且会自动调用构造函数和析构函数。
3.1 new 和 delete 操作符
new用于动态分配内存并调用对象的构造函数。delete用于释放动态分配的内存并调用对象的析构函数。
示例代码
int* ptr new int; // 动态分配一个int类型的空间
delete ptr; // 释放内存int* arr new int[10]; // 动态分配10个int类型的空间
delete[] arr; // 释放连续内存3.2 new 和 delete 的实现原理
在 C 中new 操作符会首先调用 operator new 函数来分配内存然后在该内存上调用构造函数。而 delete 操作符则会先调用析构函数清理对象资源再调用 operator delete 函数释放内存。
void* operator new(size_t size) {void* p malloc(size);if (!p) throw std::bad_alloc(); // 如果分配失败抛出异常return p;
}void operator delete(void* p) {free(p); // 释放内存
}4. new 和 malloc 的区别
虽然 new 和 malloc 都可以用于动态分配内存但它们有以下几点不同
new 是操作符malloc 是函数new 是 C 内置的操作符而 malloc 是 C 语言中的标准库函数。初始化malloc 只分配内存不会对其进行初始化而 new 不仅分配内存还会调用构造函数初始化对象。异常处理malloc 分配失败时返回 NULL而 new 分配失败时会抛出 std::bad_alloc 异常。自定义类型malloc 不能调用构造函数因此不适合分配自定义类型的对象而 new 则可以调用构造函数来初始化对象。
4.1 示例代码
class A {
public:A(int a 0) : _a(a) {std::cout A() called std::endl;}~A() {std::cout ~A() called std::endl;}
private:int _a;
};A* obj1 (A*)malloc(sizeof(A)); // 使用 malloc 分配内存但不会调用构造函数
free(obj1); // 释放内存A* obj2 new A(10); // 使用 new 分配内存并调用构造函数
delete obj2; // 释放内存并调用析构函数5. operator new 与 operator delete
operator new 和 operator delete 是全局函数用于实现 new 和 delete 的底层操作。它们通常会调用 malloc 和 free 来完成内存的分配与释放。 **### CSDN 博客C/C 内存管理详解续
接着上篇我们已经介绍了 C/C 的内存分布和基本的动态内存管理方式。本篇将继续详细讲解内存管理中的一些高级内容包括 operator new 和 operator delete 的实现原理、内置类型和自定义类型的内存管理、placement new、以及 malloc/free 与 new/delete 的更深入对比。
5. operator new 与 operator delete
operator new 和 operator delete 是系统提供的全局函数分别用于动态分配和释放内存。它们实际上是 new 和 delete 操作符的底层实现。在 C 中new 操作符首先调用 operator new 分配内存然后调用构造函数初始化对象而 delete 操作符首先调用析构函数清理对象然后调用 operator delete 释放内存。
5.1 operator new 的实现原理
operator new 的实现原理可以用如下代码描述
void* operator new(size_t size) {void* p;// 尝试分配 size 字节的内存while ((p malloc(size)) nullptr) {// 如果 malloc 分配失败尝试执行内存不足的应对措施if (_callnewh(size) 0) {// 如果没有用户设置的处理措施抛出 std::bad_alloc 异常throw std::bad_alloc();}}return p;
}可以看到operator new 本质上是通过 malloc 来分配内存的。不同的是如果内存分配失败operator new 会尝试调用用户设置的内存不足处理程序_callnewh()而 malloc 只是简单返回 NULL。
5.2 operator delete 的实现原理
operator delete 的实现则相对简单它直接调用 free 来释放内存
void operator delete(void* p) {free(p);
}6. new 和 delete 的实现原理
6.1 内置类型的内存管理
对于内置类型如 int、float 等new 和 malloc 在内存分配上是类似的。它们都分配指定大小的内存并返回指向该内存的指针。然而new 与 malloc 的不同之处在于
单个元素的分配new 可以分配单个内置类型的内存而 malloc 只能分配一块指定大小的内存。异常处理当内存分配失败时new 会抛出异常而 malloc 则返回 NULL。
示例代码
int* p1 new int; // 分配单个int类型空间
delete p1; // 释放内存int* p2 (int*)malloc(sizeof(int)); // 使用malloc分配内存
free(p2); // 释放内存6.2 自定义类型的内存管理
对于自定义类型new 和 delete 的作用更加明显因为它们除了分配和释放内存之外还会自动调用构造函数和析构函数。这一特性使得 new 和 delete 成为管理复杂对象的首选。
6.2.1 new 的工作过程
调用 operator new 分配内存为对象分配所需的内存。在已分配的内存上调用构造函数通过构造函数来初始化对象。
6.2.2 delete 的工作过程
调用析构函数析构函数会清理对象占用的资源如释放动态分配的内存等。调用 operator delete 释放内存通过 free 或类似的机制将内存归还给操作系统。
示例代码
class A {
public:A(int a) : _a(a) {std::cout Constructor called std::endl;}~A() {std::cout Destructor called std::endl;}
private:int _a;
};int main() {A* obj new A(10); // 动态分配并调用构造函数delete obj; // 调用析构函数并释放内存
}7. malloc/free 和 new/delete 的区别
malloc/free 和 new/delete 都是从堆上分配内存并且都需要用户手动释放但它们之间存在一些关键区别
7.1 语法上的区别
malloc/free 是函数malloc 和 free 是 C 标准库中的函数用于动态内存管理。new/delete 是操作符new 和 delete 是 C 的内置操作符主要用于对象的动态内存管理。
7.2 初始化的区别
malloc 不会初始化内存malloc 只是分配一块内存而不负责初始化内容。new 可以调用构造函数初始化对象new 不仅分配内存还会调用构造函数来初始化对象。
7.3 内存分配失败的处理方式
malloc 分配失败返回 NULL如果 malloc 无法分配内存它会返回 NULL程序员需要手动检查返回值。new 分配失败抛出 std::bad_alloc 异常当 new 失败时它会抛出异常而不是返回 NULL。
7.4 自定义类型的对象分配
malloc/free 不会调用构造函数和析构函数malloc 仅仅分配内存无法初始化对象也不会调用析构函数来清理对象的资源。new/delete 会调用构造函数和析构函数new 在分配内存后会调用构造函数delete 在释放内存前会调用析构函数。
示例代码对比
// 使用 malloc/free
A* obj1 (A*)malloc(sizeof(A)); // 仅仅分配内存不调用构造函数
free(obj1); // 仅仅释放内存不调用析构函数// 使用 new/delete
A* obj2 new A(10); // 分配内存并调用构造函数
delete obj2; // 调用析构函数并释放内存8. 定位 new 表达式 (Placement-new)
定位 new 表达式是一种高级用法它允许在已分配的内存上构造对象而不需要重新分配内存。典型的使用场景是内存池或者需要精细控制内存分配的地方。
8.1 定位 new 的使用方式
定位 new 表达式的语法如下
new (place_address) type;其中 place_address 是内存的地址而 type 是需要构造的对象类型。
示例代码
class A {
public:A(int a 0) : _a(a) {std::cout A() called std::endl;}~A() {std::cout ~A() called std::endl;}
private:int _a;
};int main() {void* buffer malloc(sizeof(A)); // 分配一块内存A* obj new(buffer) A(10); // 在指定的内存上构造对象obj-~A(); // 手动调用析构函数free(buffer); // 释放内存
}8.2 定位 new 的应用场景
定位 new 常用于内存池管理。内存池是一种预先分配大量内存的技术通过在这块内存上手动管理对象的分配和释放能够极大提高程序的性能。特别是对于实时系统或嵌入式系统使用内存池可以避免频繁调用操作系统的内存管理函数减少系统开销。 结语
通过以上两部分的详细讲解我们全面介绍了 C/C 的内存管理机制。从基本的 malloc/free 到 new/delete再到定位 new 表达式内存管理的不同方式各有适用场景。理解并合理使用这些机制能够帮助开发者编写高效且健壮的代码特别是在需要精确控制内存分配的场景中正确的内存管理能够极大提升程序的性能。
在实践中建议程序员根据具体需求选择适当的内存管理方式避免内存泄漏和资源浪费确保程序的健壮性和可维护性。