c++动态内存分布以及和C语言的比较
文章目录
- 前言
- 一.c/c++内存分布
- C语言的动态内存管理方式
- C++内存管理方式
- operator new和operator delete函数
- malloc/free和new/delete的区别
- 定位new
- 内存泄漏的危害
- 总结
前言
c++是在c的基础上开发出来的,所以关于内存管理这一方面是兼容c的,比如以前C语言的malloc等等都是可以继续使用的,但是靠C语言以前的东西是解决不了c++中的问题的,比如自定义类型空间的开辟以及自定义类型如何释放空间等等,所以在内存管理这方面c++又与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是全局变量,全局变量的static修饰的变量都放在静态区,staticGlobalVar既是全局变量又是静态变量所以还是放在静态区,staticVar虽然在局部作用域中但是静态变量都是放在静态区的,localVar是局部变量,局部变量放在栈中,num1是存放10个整形的数组也放在栈中。所以前5个的答案是C C C A A
char 2[]是一个数组,同理是放在栈中的,*char2对数组名进行解引用,数组名代表首元素地址,也就是a存放的地方,数组都在栈中那么a肯定也是存放在栈中了。pchar3是一个指针变量,局部变量都是存放在栈中的,*pchar3是对这个指针变量进行解引用,解引用后找到其实际内容,虽然变量是在栈中开辟的,但是由于保存的是常量所以常量是放在常量区,所以*ptr3在代码段中。ptr1同样是指针变量,指针变量在栈中开辟,*ptr1是ptr1所指向的空间,使用malloc开辟的空间是在堆中,所以*ptr1是在堆中。这6道题的答案为:A A A D A B

num1是个有10整形的数组,所以大小为40.char2是个字符数组,存放abcd\0共占用5个字节。strlen(char2)为4因为strlen会算到\0之前不包含\0.pchar3是个指针,指针是4/8字节。pchar3的长度也为4,ptr1是个指针大小也为4/8。所以答案为:40 5 4 4/8 4 4/8
栈又叫堆栈,非静态局部变量/函数参数/返回值等等,栈是向下增长的。
内存映射段是高效的I/O映射方式,用于装载一个共享的动态内存库,用户可使用系统接口创建共享共享内存,做进程间通信。
堆用于程序运行时动态内存分配,堆是可以上增长的。
数据段:存储全局数据和静态数据
代码段:可执行的代码/只读常量
C语言的动态内存管理方式
C语言使用malloc/calloc/realloc/free管理内存,那么malloc/calloc/realloc有什么区别呢?
malloc开辟空间不会进行初始化,calloc会初始化为0。realloc分为原地扩容和异地扩容,当原来扩容的空间后面有足够的空间的时候就在原来空间的后面直接扩容,如果空间不够则先找到一块足够大的空间然后将原来空间的数据拷贝到新空间再将旧空间释放掉。
c++内存管理方式

当然new是可以手动初始化的,方式如下:

那么开连续的空间是什么样的呢?
当然连续的也可以初始化,方式如下:

我们使用new开辟空间一定要用delete去释放,尤其是自定义类型的时候因为delete会调用析构函数如果你在这里使用free释放空间,那么析构函数中没有释放的空间就会造成内存泄漏。
class A
{
public:A(int a = 0): _a(a){cout << "A():" << this << endl;}~A(){cout << "~A():" << this << endl;}
private:int _a;
};
int main()
{A* pp = new A(1);delete pp;return 0;
} 
operator new与operator delete 函数
我们听名字以为这是运算符重载,其实不是这里只是用了一样的词罢了,这里与运算符重载没有任何关联。new和delete是用户进行动态内存申请和释放的操作符,operator new和operator delete是系统提供的全局函数,new在底层调用operator new全局函数来申请空间,delete在底层通过operator delete释放空间。当然还有operator new[]和operator delete[]是为了匹配new【】和delete【】。

那么operator new和operator delete的底层是怎么实现的呢?
operator new:该函数实际通过malloc来申请空间,当malloc申请空间成功时直接返回,申请空间失败,尝试执行空间不足应对措施,如果该应对措施用户设置了,则继续申请,否则抛异常。
class Stack
{
public:Stack(){cout << "stack()" << endl;_a = new int[4];top = 0;capacity = 4;}~Stack(){cout << "~Stack" << endl;delete[] _a;_a = nullptr;top = capacity = 0;}private:int* _a;int top;int capacity;
};
int main()
{Stack sl; //自定义类型会去调用构造和析构//这里的指针类型为内置类型,所以需要手动释放空间Stack* pst = new Stack;delete pst;return 0;
} 如上图所示,指针类型为内置类型不管是什么类型的指针都是内置类型所以不会像自定义类型一样调用构造和析构,当我们用pst开辟空间的时候和sl有什么不一样呢?看下图:

如果我们混着用比如释放的时候用free,free是不会调用析构函数的所以堆中绿色_a的空间没办法释放直接将pst的空间释放后再也找不到_a的空间了,这就造成了内存泄漏。
malloc/free和new/delete的区别
1.malloc/free对于自定义类型不会调用其构造和析构函数,new/delete对于自定义类型会调用其构造函数和析构函数。
2.malloc开辟空间的时候不能初始化,new可以手动初始化。
3.malloc/free是函数,new/delete是操作符。
4.malloc申请空间时需要手动计算其空间大小,new申请空间编译器会自动计算,如果是多个对象new只需要在后面[]里加上对象个数即可。
5.malloc的返回值为void*,使用时必须将malloc强制转换,new不需要new后面就是类型。
6.malloc申请空间失败会返回空指针,而new申请空间失败会抛异常。
定位new
定位new表达式是在已分配的原始内存空间中调用构造函数初始化一个对象。
使用格式:
new(place_address)type或者new(place_address)type(initializer-list)
place_address必须是一个指针。initializer-list是类型的初始化列表
使用场景:
定位new表达式在实际中一般是配合内存池使用。因为内存池分配出的内存没有初始化,所以如果是自定义类型的对象,需要使用new的定义表达式进行显式调构造函数初始化。

如上图,因为操作系统是给所有的资源分配空间所以当你去向操作系统申请空间的时候会慢一些,这个时候可以直接像自己的内存池要内存,内存池的内存也是从堆里来的,当内存池有内存的时候就会把空间给你,如果没有内存内存池就会去找操作系统,然后内存池找操作系统要内存,内存池要的内存一般比你申请的空间要大,因为内存池要保证内存够用并且下一次来申请还有足够的内存。内存池的方式相比找操作系统消耗会变小。下面是定位new的使用样例:
class A
{
public:A(int a = 0): _a(a){cout << "A():" << this << endl;}~A(){cout << "~A():" << this << endl;}
private:int _a;
};
int main()
{A aa;A* p1 = (A*)malloc(sizeof(A));if (p1 == NULL){perror("malloc:");exit(-1);}//定位new 对已有的空间初始化。new(p1)A(1);A* p2 = new A;p1->~A();free(p1);delete p2;return 0;
} 图中我们用malloc开的空间是没办法初始化的,所以使用定位new对p1进行了初始化。p1既然既然是A*的指针那么就可以访问A类的公有函数,而这样的初始化其实我们用new就可以搞定,因为new对自定义类型会去调用构造函数。
内存泄漏的危害
void MemoryLeaks()
{// 1.内存申请了忘记释放int* p1 = (int*)malloc(sizeof(int));int* p2 = new int;// 2.异常安全问题int* p3 = new int[10];Func(); // 这里Func函数抛异常导致 delete[] p3未执行,p3没被释放.delete[] p3;
} int main()
{int* p = new int[10];// 将该函数放在main函数之后,每次程序退出的时候就会检测是否存在内存泄漏_CrtDumpMemoryLeaks();return 0;
} 那么怎么避免内存泄漏呢?
总结
c/c++的内存管理最大的区别在于如何处理自定义类型,由于c++要兼容c所以做了很多的取舍比如定位new等,本章的关键在于malloc/free与new/delete的区别并且正确匹配的使用new和malloc,只有养成良好的编码习惯才能减少内存泄漏的危害
相关文章:
c++动态内存分布以及和C语言的比较
文章目录 前言一.c/c内存分布 C语言的动态内存管理方式 C内存管理方式 operator new和operator delete函数 malloc/free和new/delete的区别 定位new 内存泄漏的危害总结前言 c是在c的基础上开发出来的,所以关于内存管理这一方面是兼容c的&…...
软考高级信息系统项目管理师系列之三十一:项目变更管理
软考高级信息系统项目管理师系列之三十一:项目变更管理 一、项目变更管理内容二、项目变更管理基本概念1.项目变更管理定义2.项目变更产生的原因3.项目变更的分类三、项目变更管理的原则和工作流程1.项目变更管理的原则2.变更管理的组织机构3.变更管理的工作程序四、项目变更管…...
【Vue3源码】第二章 effect功能的完善补充
【Vue3源码】第二章 effect功能的完善补充 前言 上一章节我们实现了effect函数的功能stop和onstop,这次来优化下stop功能。 优化stop功能 之前我们的单元测试中,stop已经可以成功停止了响应式更新(清空了收集到的dep依赖) st…...
CHAPTER 2 Web Server - apache(httpd)
Web Server - httpd2.1 http2.1.1 协议版本2.1.2 http报文2.1.3 web资源(web resource)2.1.4 一次完整的http请求处理过程2.1.5 接收请求的模型2.2 httpd配置2.2.1 MPM(多进程处理模块)1. 工作模式2. 切换MPM3. MPM参数配置2.2.2 主配置文件1. 基本配置2. 站点访问控制常见机制…...
【Vagrant】下载安装与基本操作
文章目录概述软件安装安装VirtualBox安装Vagrant配置环境用Vagrant创建一个VMVagrantfile文件配置常用命令概述 Vagrant是一个创建虚拟机的技术,是用来创建和管理虚拟机的工具,本身自己并不能创建管理虚拟机。创建和管理虚拟机必须依赖于其他的虚拟化技…...
常用类(五)System类
(1)System类常见方法和案例: (1)exit:退出当前程序 我们设计的代码如下所示: package com.ypl.System_;public class System_ {public static void main(String[] args) {//exit: 退出当前程序System.out.println("ok1"…...
Navicat Premium 安装 注册
Navicat Premium 一.Navicat Premium的安装 1.暂时关闭windows的病毒与威胁防护弄完再开,之后安装打开过程中弹窗所有警告全部允许,不然会被拦住 2.下载安装包,解压 链接:https://pan.baidu.com/s/1X24VPC4xq586YdsnasE5JA?pwdu4vi 提取码…...
回溯算法总结
首先回溯算法本身还是一个纯暴力的算法,只是回溯过程可能比较抽象,导致大家总是感觉看到的相关题目做的不是很顺畅,回溯算法一般来说解决的题目有以下几类:组合问题:lq77、lq17、lq39、lq40、lq216、切割问题ÿ…...
ccc-pytorch-基础操作(2)
文章目录1.类型判断isinstance2.Dimension实例3.Tensor常用操作4.索引和切片5.Tensor维度变换6.Broadcast自动扩展7.合并与分割8.基本运算9.统计属性10.高阶OP大伙都这么聪明,注释就只写最关键的咯1.类型判断isinstance 常见类型如下: a torch.randn(…...
独居老人一键式报警器
盾王居家养老一键式报警系统,居家养老一键式报警设备 ,一键通紧急呼救设备,一键通紧急呼救系统,一键通紧急呼救器 ,一键通紧急呼救终端,一键通紧急呼救主机终端产品简介: 老人呼叫系统主要应用于…...
软考案例分析题精选
试题一:阅读下列说明,回答问题1至问题4,将解答填入答题纸的对应栏内。某公司中标了一个软件开发项目,项目经理根据以往的经验估算了开发过程中各项任务需要的工期及预算成本,如下表所示:任务紧前任务工期PV…...
基于SpringBoot+vue的无偿献血后台管理系统
基于SpringBootvue的无偿献血后台管理系统 ✌全网粉丝20W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取项目下载方式🍅 一、项目背…...
详解js在事件中,如何传递复杂数据类型(数组,对象,函数)
文章目录 前言一、何谓预编译,变量提升?二、复杂数据类型的传递 1.数组2.对象3.函数总结前言 在JavaScript这门编程语言学习中,如何传参,什么是变量提升,js代码预编译等等。要想成为一名优秀的js高手,这些内…...
高并发架构 第一章大型网站数据演化——核心解释与说明。大型网站技术架构——核心原理与案例分析
大型网站架构烟花发展历程1.1.1初始阶段的网站构架1.1.2应用服务和数据服务分离1.1.3使用缓存改善网络性能1.1.4使用应用服务器集群改善网站的并发处理能力1.1.5数据库读写分离1.1.6使用反向代理和cdn加速网站相应1.1.1初始阶段的网站构架 大型网站都是由小型网站一步步发展而…...
VPP接口INPUT节点运行数据
在设置virtio接口接收/发送队列函数的最后,更新接口的运行数据。 void virtio_vring_set_rx_queues (vlib_main_t *vm, virtio_if_t *vif) { ...vnet_hw_if_update_runtime_data (vnm, vif->hw_if_index); } void virtio_vring_set_tx_queues (vlib_main_t *vm,…...
RabbitMQ学习(九):延迟队列
一、延迟队列概念延时队列中,队列内部是有序的,最重要的特性就体现在它的延时属性上,延时队列中的元素是希望 在指定时间到了以后或之前取出和处理。简单来说,延时队列就是用来存放需要在指定时间内被处理的 元素的队列。其实延迟…...
TCP并发服务器(多进程与多线程)
欢迎关注博主 Mindtechnist 或加入【Linux C/C/Python社区】一起探讨和分享Linux C/C/Python/Shell编程、机器人技术、机器学习、机器视觉、嵌入式AI相关领域的知识和技术。 TCP并发服务器(多进程与多线程)1. 多进程并发服务器(1)…...
第1章 Memcached 教程
Memcached是一个自由开源的,高性能,分布式内存对象缓存系统。 Memcached是以LiveJournal旗下Danga Interactive公司的Brad Fitzpatric为首开发的一款软件。现在已成为mixi、hatena、Facebook、Vox、LiveJournal等众多服务中提高Web应用扩展性的重要因素…...
【2022.12.9】Lammps+Python 在计算g6(r)时遇到的问题
目录写在前面绘制g6( r )执行步骤【updated】如何检查图像的正确性:不是编程问题,而是数学问题的一个小bug废稿2则:写在前面 全部log: 【2022.11.16】LammpsPythonMATLAB在绘制维诺图时遇到的问题 绘制g6( r )执行步骤【updated…...
MySQL使用C语言连接
文章目录MySQL使用C语言连接引入库下载库文件在项目中使用库使用库连接数据库下发SQL请求获取查询结果MySQL使用C语言连接 引入库 要使用C语言连接MySQL,需要使用MySQL官网提供的库。 下载库文件 下载库文件 首先,进入MySQL官网,选择DEVEL…...
从ChatGPT到Sora:拆解Transformer架构演进,看MHA、MQA、GQA和KV Cache如何决定大模型推理速度
从ChatGPT到Sora:Transformer架构演进与推理加速实战 在生成式AI爆发的时代,Transformer架构已成为大模型的核心引擎。从ChatGPT的惊艳表现到Sora的视频生成突破,背后都离不开对注意力机制的持续优化。本文将深入剖析MHA、MQA、GQA等关键技术…...
基于STM32的校园一卡通系统设计与实现
1. 项目概述1.1 项目开发背景作为一名嵌入式系统开发者,我最近完成了一个基于STM32的校园一卡通系统项目。这个项目的灵感来源于我在大学期间亲身经历的多卡困扰——每天要带着学生证、饭卡、图书证等一堆卡片,不仅容易丢失,使用起来也很不方…...
Windows系统安装OpenClaw:千问3.5-9B联调避坑指南
Windows系统安装OpenClaw:千问3.5-9B联调避坑指南 1. 为什么选择WindowsOpenClaw组合 作为一个长期在Windows环境下工作的开发者,我一直在寻找能够提升日常效率的AI助手方案。直到遇到OpenClaw这个开源的本地化AI智能体框架,它让我看到了将…...
Greasy Fork:开源用户脚本平台如何重塑你的浏览器体验
Greasy Fork:开源用户脚本平台如何重塑你的浏览器体验 【免费下载链接】greasyfork An online repository of user scripts. 项目地址: https://gitcode.com/gh_mirrors/gr/greasyfork 在当今互联网时代,浏览器已成为我们获取信息、处理工作的核心…...
像素幻梦·创意工坊实操手册:批量生成任务队列管理与异步导出机制
像素幻梦创意工坊实操手册:批量生成任务队列管理与异步导出机制 1. 认识像素幻梦创意工坊 Pixel Dream Workshop(像素幻梦创意工坊)是一款基于FLUX.1-dev扩散模型的像素艺术生成工具。它采用16-bit像素风格的现代化界面设计,为创…...
音乐格式自由革命:NCMDump终极指南让你轻松解锁网易云加密音乐
音乐格式自由革命:NCMDump终极指南让你轻松解锁网易云加密音乐 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为网易云音乐下载的歌曲只能在特定客户端播放而烦恼吗?你是否曾经因为NCM格式的限制而无法在…...
企业级RESTful API设计终极指南:10个进阶技巧助力构建高性能接口
企业级RESTful API设计终极指南:10个进阶技巧助力构建高性能接口 【免费下载链接】restful-api-design-references RESTful API 设计参考文献列表,可帮助你更加彻底的了解REST风格的接口设计。 项目地址: https://gitcode.com/gh_mirrors/re/restful-a…...
从工厂老师傅到代码新手:我用VisionPro+C#给老旧视觉检测设备做了个“智能升级”
从工厂老师傅到代码新手:我用VisionProC#给老旧视觉检测设备做了个“智能升级” 在工业自动化车间里,那些服役多年的视觉检测设备就像经验丰富的老师傅——它们可能外壳陈旧、操作界面简陋,但核心算法依然精准可靠。我作为设备维护工程师&…...
renderer数学库解析:3D图形学中的向量、矩阵与四元数
renderer数学库解析:3D图形学中的向量、矩阵与四元数 【免费下载链接】renderer A shader-based software renderer written from scratch in C89 项目地址: https://gitcode.com/gh_mirrors/re/renderer 想要从零开始构建一个完整的3D渲染器吗?r…...
ChatGLM3-6B零基础部署:Streamlit重构版5分钟快速搭建本地智能助手
ChatGLM3-6B零基础部署:Streamlit重构版5分钟快速搭建本地智能助手 1. 引言:为什么你需要一个本地专属的AI助手? 想象一下,你正在写一份重要的技术报告,需要快速查询某个编程概念;或者你在分析一份长达几…...
