深入理解C/C++的内存管理

news2025/1/19 8:07:54

在C和C++中,高效的内存管理是编写性能优化和资源高效利用程序的关键。本文将深入探讨C/C++内存管理的各个方面,包括内存的分布、C语言和C++中的动态内存管理方式,以及newdelete操作符的使用

C/C++内存分布

C和C++程序的内存可以分为以下几个区域:

  • 栈(Stack):自动存储局部变量。当函数被调用时,局部变量在栈上创建,函数返回时,这些变量被销毁。
  • 堆(Heap):用于动态内存分配。与栈不同,堆上的内存分配和释放需要手动管理。
  • 全局/静态存储区:存放全局变量和静态变量。这部分内存在程序启动时分配,在程序结束时释放。
  • 文字常量区:常量字符串等常量数据存放的地方。它们在程序生命周期内不变。
  • 程序代码区:存放程序执行代码的内存区域。

 

 

理解这些区域对于避免内存泄漏和优化程序性能至关重要。

C语言中动态内存管理方式

C语言提供了几种动态内存管理的方法,包括:

  • malloc:分配指定大小的内存块。分配的内存未初始化,可能包含垃圾数据。
  • calloc:分配并初始化指定数量的内存块。初始化为零。
  • realloc:重新分配之前分配的内存块的大小。
  • free:释放之前分配的内存块。

这些函数允许程序在运行时根据需要分配和释放内存,但也需要开发者负责管理这些内存,以避免内存泄漏。

#include <stdlib.h>

void dynamicMemoryExample() {
    int* ptr = (int*)malloc(sizeof(int) * 4); // 分配内存
    if (ptr != NULL) {
        for (int i = 0; i < 4; i++) {
            ptr[i] = i; // 使用内存
        }
    }
    free(ptr); // 释放内存
}

 

C++中动态内存管理

C++提高了动态内存管理的抽象层次,通过newdelete操作符提供更为直观和安全的方式来处理内存。

  • 使用new分配内存不仅会分配内存,还会调用对象的构造函数,这提供了初始化对象的机会。
  • 使用delete释放内存时,会调用对象的析构函数,然后释放内存,这提供了清理资源的机会
#include <iostream>

void dynamicMemoryExampleInCpp() {
    int* ptr = new int(10); // 动态分配内存并初始化
    std::cout << *ptr << std::endl; // 使用内存
    delete ptr; // 释放内存,并调用析构函数
}

 

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[] ,注意:匹配起来使用。

 

newdelete操作自定义类型 

class A
{
public:
 A(int a = 0)
 : _a(a)
 {
 cout << "A():" << this << endl;}
 ~A()
 {
 cout << "~A():" << this << endl;
 }
private:
 int _a;
};
int main()
{
 // new/delete 和 malloc/free最大区别是 new/delete对于【自定义类型】除了开空间
还会调用构造函数和析构函数
 A* p1 = (A*)malloc(sizeof(A));
 A* p2 = new A(1);
 free(p1);
 delete p2;
 // 内置类型是几乎是一样的
 int* p3 = (int*)malloc(sizeof(int)); // C
 int* p4 = new int;
free(p3);
delete p4;
 A* p5 = (A*)malloc(sizeof(A)*10);
 A* p6 = new A[10];
 free(p5);
 delete[] p6;
 return 0;
}
注意:在申请自定义类型的空间时,new会调用构造函数,delete会调用析构函数,而malloc
free不会

 

operator new与operator delete函数

在C++中,newdelete不仅仅是操作符,它们背后实际上是调用了operator newoperator delete函数。这两个函数负责分配和释放动态内存。重要的是,C++允许开发者重载这些函数来提供自定义的内存管理策略。

自定义内存管理

自定义内存管理通常用于优化性能,例如通过实现特定的内存池来避免频繁地向操作系统请求小块内存。这样可以显著减少内存碎片以及提高内存分配和释放的效率。

#include <iostream>
#include <cstdlib>

void* operator new(size_t size) {
    std::cout << "Custom new for size: " << size << std::endl;
    return malloc(size);
}

void operator delete(void* memory) noexcept {
    std::cout << "Custom delete" << std::endl;
    free(memory);
}

通过这个简单的例子,我们看到了如何拦截所有的newdelete调用,以便在分配和释放内存时执行自定义逻辑

new和delete的实现原理

new操作符在底层调用operator new函数来分配内存,并在成功分配内存后调用对象的构造函数。相似地,delete操作符首先调用对象的析构函数,然后调用operator delete函数来释放内存。

这种分离使得newdelete不仅仅关注内存的分配和释放,还能确保对象生命周期的正确管理。

如果申请的是内置类型的空间, new malloc delete free 基本类似,不同的地方是:
new/delete 申请和释放的是单个元素的空间, new[] delete[] 申请的是连续空间,而且 new 在申
请空间失败时会抛异常, malloc 会返回 NULL
自定义类型
new 的原理
1. 调用 operator new 函数申请空间
2. 在申请的空间上执行构造函数,完成对象的构造
delete 的原理
1. 在空间上执行析构函数,完成对象中资源的清理工作
2. 调用 operator delete 函数释放对象的空间
new T[N] 的原理
1. 调用 operator new[] 函数,在 operator new[] 中实际调用 operator new 函数完成 N 个对
象空间的申请
2. 在申请的空间上执行 N 次构造函数
delete[] 的原理
1. 在释放的对象空间上执行 N 次析构函数,完成 N 个对象中资源的清理
2. 调用 operator delete[] 释放空间,实际在 operator delete[] 中调用 operator delete 来释
放空间

 

也就是说当调用delete[]的时候,地址的第一个字节处存放的是n,也就是需要调用n次析构,如果我们使用的是delete,默认从当前位置开始析构,那么位置就会出错。 

 

定位new表达式(placement-new)

定位new表达式是C++中的一个高级特性,允许在已分配的内存上构造对象。这对于内存池、缓存管理等场景非常有用,因为它允许重复使用已分配的内存来创建新对象,避免了频繁的内存分配和释放操作。

#include <new> // 必须包含这个头文件

char buffer[1024]; // 预分配内存

void placementNewExample() {
    int* p = new (buffer) int(10); // 在buffer上构造int对象
    // 使用p...
}

 

使用定位new表达式时,需要确保操作的内存足够大且正确对齐,以容纳指定类型的对象。

常见面试题

内存区域划分

问:请描述C/C++程序中的内存区域划分。

答:C/C++程序的内存分为栈、堆、全局/静态存储区、文字常量区和程序代码区。

动态内存管理

问:mallocnew的区别是什么?

答:malloc仅分配内存,不调用构造函数;new分配内存的同时调用构造函数初始化对象。相应地,freedelete的区别在于delete会先调用析构函数再释放内存。

定位new

问:什么是定位new表达式,它有什么用途?

答:定位new表达式允许在已分配的内存上构造对象。这在需要在特定位置创建对象,或者在内存池、缓存管理等场景下重复使用内存时非常有用。


通过本文,我们深入探讨了C/C++中的内存管理,从基本的内存区域划分到高级特性如定位new表达式,以及如何通过重载operator newoperator delete来实现自定义内存管理策略。理解这些概念不仅对于写出高性能的C/C++代码至关重要,也是面试中常见的问题。希望这篇博客能帮助你在C/C++内存管理方面达到新的高度!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1568916.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Linux】-进程知识铺垫①计算机硬件的组织:冯诺依曼体系结构详细解读②关于操作系统对软硬件及用户的意义

目录 ​编辑 1.关于计算机的体系结构 1.1 冯诺依曼体系结构的诞生 2.冯诺依曼体系结构 2.1 cpu:运算器&#xff1a;更多的是让cpu具有特殊的数据计算功能&#xff1a; 2.2 控制器 2.3输入设备 2.4输出设备 3.计算机各个硬件设备之间的关系 4.内存与计算机效率 5.关于为什么总说…

AI智能校色解决方案,专业级画质提升

由于拍摄环境、设备性能以及编辑经验等多种因素的影响&#xff0c;视频画质往往难以达到理想状态。这时&#xff0c;一款高效、智能的校色解决方案就显得尤为重要。美摄科技凭借深厚的图像处理技术和AI算法研发实力&#xff0c;推出了全新的AI智能校色解决方案&#xff0c;助力…

Kubernetes(k8s)核心资源解析:Pod详解

Kubernetes核心资源解析&#xff1a;Pod详解 1、什么是Pod&#xff1f;2、Pod 的组成3、Pod 如何管理多个容器4、Pod 的网络5、Pod 的存储方式6、Pod 的工作方式6.1 自主式 Pod6.2 监控和管理 Pod6.3 Pod 的创建流程 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收…

力扣热题100_链表_2_两数相加

文章目录 题目链接解题思路解题代码 题目链接 2. 两数相加 给你两个 非空 的链表&#xff0c;表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的&#xff0c;并且每个节点只能存储 一位 数字。 请你将两个数相加&#xff0c;并以相同形式返回一个表示和的链表。 …

网络安全 | 什么是云安全?

关注WX&#xff1a;CodingTechWork 云安全-介绍 云安全是为了解决企业安全所面临的外部和内部威胁&#xff0c;它是一组程序和技术的集合。企业在实施其数字化转型策略&#xff0c;并将各种云端工具和服务纳入企业基础架构中时&#xff0c;需要云安全保障业务顺利进行。 云计…

ComfyUI ClipSeg插件报错- resize_image出错应该怎么办

上一篇刚介绍了这个插件&#xff0c;结果emm..很快发现事情并不简单...结果又报错了。 后台报错信息&#xff1a; Unused or unrecognized kwargs: padding. !!! Exception during processing !!! Traceback (most recent call last): File "F:\ComfyUI-aki\execution.p…

蓝桥杯练习笔记(十七)

蓝桥杯练习笔记&#xff08;十七&#xff09; 一、 输入样例 7 7 1000001 0100010 0010100 0001AAA 00010A0 00010A0 00010A0蓝桥官网题解&#xff1a; 该题解是用了三个循环分别对三个方向的相同字符的长度进行统计&#xff0c;找出最大长度&#xff0c;最后对找出的最长Y进…

Finite Element Procedures K.J.Bathe 【教材pdf+部分源码】|有限元经典教材 | 有限元编程

专栏导读 作者简介&#xff1a;工学博士&#xff0c;高级工程师&#xff0c;专注于工业软件算法研究本文已收录于专栏&#xff1a;《有限元编程从入门到精通》本专栏旨在提供 1.以案例的形式讲解各类有限元问题的程序实现&#xff0c;并提供所有案例完整源码&#xff1b;2.单元…

uni-app 实现仿微信界面【我的+首页聊天列表+长按菜单功能+添加菜单功能】+ 附源码

目录 【微信首页聊天列表】界面 【我的】界面 源代码&#xff1a; 文后附完整代码&#xff0c;支持一键导入 HBuilderX 示例体验 【微信首页聊天列表】界面 仿造【微信首页聊天列表 长按菜单功能 右上角添加按钮弹窗功能】&#xff0c;使用 uni-app 开发&#xff0c; 一…

ARM IHI0069F GIC architecture specification (5)

Ch2 中断分配与路由 2.1 The Distributor and Redistributors Distributor 为 SPI 提供路由配置&#xff0c;并保存所有关联的路由和优先级信息。 Redistributor 提供 PPI 和 SGI 的配置设置。 Redistributor总是在有限的时间内向 CPU 接口呈现具有最高优先级的待处理中断。 …

算法 day29 回溯5

491 非递减子序列 给你一个整数数组 nums &#xff0c;找出并返回所有该数组中不同的递增子序列&#xff0c;递增子序列中 至少有两个元素 。你可以按 任意顺序 返回答案。 数组中可能含有重复元素&#xff0c;如出现两个整数相等&#xff0c;也可以视作递增序列的一种特殊情…

蓝桥杯(4):python动态规划DF[1]

动态规划相当于正着想&#xff1f;dfs主要适用于位置的变化&#xff1f; 子问题&#xff01;状态&#xff0c;状态转移方程 1 一维DP 1.1 定义 重叠子问题&#xff01;转换成子问题 &#xff0c;与记忆化搜索很像 1.2 例子 1.2.1 上楼梯 子问题到最终的问题只能跨一步&…

arm裸机-1、定时器pwm

时钟配置 我们使用s3c2440&#xff0c;主频12M&#xff0c;查看用户手册 通过锁相环抬升到400MHZ&#xff0c;分成三条通路&#xff0c;通过HHDIVN和PDIVN配置频率比&#xff0c;这个频率比配置手册已经给出。 配置MPLL主频400Mhz&#xff0c; 通过这个公式算出MPLL s、p、m都…

LeetCode 1379.找出克隆二叉树中的相同节点:二叉树遍历

【LetMeFly】1379.找出克隆二叉树中的相同节点&#xff1a;二叉树遍历 力扣题目链接&#xff1a;https://leetcode.cn/problems/find-a-corresponding-node-of-a-binary-tree-in-a-clone-of-that-tree/ 给你两棵二叉树&#xff0c;原始树 original 和克隆树 cloned&#xff0…

《QT实用小工具·五》串口助手

1、概述 源码放在文章末尾 该项目实现了串口助手的功能&#xff0c;可在界面上通过串口配置和网络配置进行串口调试。 基本功能 支持16进制数据发送与接收。支持windows下COM9以上的串口通信。实时显示收发数据字节大小以及串口状态。支持任意qt版本&#xff0c;亲测4.7.0 到…

《数字图像处理》-上机 5 图像阈值化处理、霍夫变换及形态学算法

一、上机目的 学习图像阈值化处理、霍夫变换、形态学算法及编程实现方法 二、相关知识及练习 1、图像阈值化处理 图像阈值化&#xff08;Binarization&#xff09;旨在剔除掉图像中一些低于或高于一定值的像素&#xff0c;从而提 取图像中的物体&#xff0c;将图像的背景和…

【JavaScript】函数 ⑦ ( 函数定义方法 | 命名函数 | 函数表达式 )

文章目录 一、函数定义方法1、命名函数2、函数表达式3、函数表达式示例 一、函数定义方法 1、命名函数 定义函数的标准方式 就是 命名函数 , 也就是之前讲过的 声明函数 ; 函数 声明后 , 才能被调用 ; 声明函数的语法如下 : function functionName(parameters) { // 函数体 …

探索前端架构:MVC、MVVM和MVP模式

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

qt通过setProperty设置样式表笔记

在一个pushbutton里面嵌套两个label即可&#xff0c;左侧放置图片label&#xff0c;右侧放置文字label&#xff0c;就如上图所示&#xff1b; 但是这时的hover&#xff0c;press的伪状态是没有办法“传递”给里面的控件的&#xff0c;对btn的伪状态样式表的设置&#xff0c;是不…

提升工作效率:B端工作台设计基础详解

随着互联网和信息技术的快速发展&#xff0c;越来越多的企业开始以数字化、智能化的方式管理和运营自己的业务。B端工作台设计作为企业应用的重要组成部分&#xff0c;越来越受到重视。本文将从三个方面对B端工作台设计进行全面分析。让我们看看。 1. B端工作台设计原则 B端工…