C++内存分配策略

目录

基础概念

内存布局

分配方式

实现

1.new和delete

2.利用空间配置器alloc

3.用malloc和free

4.静态内存分配


基础概念

在讲内存分配之前,先对一些基础概念进行阐述,以便能更好的讨论问题

内存布局

代码编译为可执行程序后运行占用的内存可以分为以下几个区域:

1.栈区(stack) :  由编译器自动分配释放,用于存放函数的参数值,局部变量的值等;在一个进程中,位于用户虚拟地址空间顶部的是用户栈,编译器用它来实现函数的调用;栈上的内存在函数返回时就会自动释放;栈区的内存地址延伸方式从高地址向地址;栈内存的大小通常是有限的,所以大量使用可能导致栈溢出。
2.堆区(heap) : 一般由程序员分配释放,若程序员不释放,程序结束时可能由OS(操作系统)回收;堆可以动态地扩展和收缩,注意它与数据结构中的堆是两回事,分配方式倒是类似于链表。
3.全局区(静态区、static): 全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。程序结束后由系统释放。
4.文字常量区 : 常量字符串就是放在这里的,程序结束后由系统释放。
5. 程序代码区 : 存放函数体的二进制代码,代码里面的全局函数和类成员函数编译后就是存在这个区域。

一个可执行程序,在不运行时占用磁盘空间的是全局区、文字常量区和程序代码区,运行后栈区和堆区在内存里面才划分出来工作。下面是区域划分图:

实例分析

int  g_a=0;   //全局初始化区 static int g_b = 0; //全局变量,static限制了使用区域char *g_p1;   //全局未初始化区    static void func(int x, int y) //x,y是形参,栈区
{static int x1 =0;//局部(静态)初始化区   int x2 = 0;  //局部变量,栈区 
}int  main()    
{    int  x; //局部变量,存放在栈区   char  s[]="abc"; //局部变量,栈    char  *p1; //局部变量,栈    char  *p2="abcdef"; //"abcdef/0"在常量区,p3在栈上。    p1 =  (char  *)malloc(23);  //分配得来得23和25字节的区域就在堆区 strcpy(p1,"abcdef"); //"abcdef\0"放在常量区,编译器可能会将它与p2所指向的"abcdef"  优化成一个地方int* p4 = new int(2);  //p4是局部变量,存放在栈区,p4指向的内存是堆区
}    

分配方式

C/C++内存分配方式有3种:

1.从静态存储区域分配:  是在程序编译和链接时就确定好的内存;这些内存在程序整个运行期间都存在,如全局变量,static变量等。
2.在栈上创建:在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放,栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限,如数组,局部变量,形参。 
3.从堆上分配:亦称动态内存分配 ,是在程序加载、调入、执行的时候分配/回收的内存;程序在运行的时候用 malloc 或 new 申请任意多少的内存,程序员自己负责在何时用 free 或 delete 释放内存。动态内存的生存期由程序员决定 ,使用非常灵活,但如果在堆上分配了空间,就有责任回收它,否则运行的程序会出现内存泄漏,频繁地分配和释放不同大小的堆空间将会产生堆内碎块。

实现

1.new和delete

在C++里面这种方式是用的最多的,代码如下:

    template <class T> struct CreateUsingNew{template <typename... Args>static T* Create(Args&&... args){ return new T(std::forward<Args>(args)...); }static void Destroy(T* p){ delete p; }};

2.利用空间配置器alloc

在STL中空间配置器的4个函数:

内存的配置:alloc::allocate();
对象的构造:alloc::construct();
对象的析构:alloc::destroy();
内存的释放:alloc::deallocate();

 利用空间分配器分配内存的代码如下:

    template<template<class> class Alloc>struct CreateUsing{template <class T>struct Allocator{static Alloc<T> allocator;template <typename... Args>static T* Create(Args&&... args){return new (allocator.allocate(1)) T(std::forward<Args>(args)...);}static void Destroy(T* p){//allocator.destroy(p);p->~T();allocator.deallocate(p,1);}};};

STL中容器默认空间分配器为std::allocator<_Tp>,内存分配和释放的接口allocate和deallocate内部实现只是将::operator new和::operator delete进行封装,没用做特殊处理;如果还想深入了解STL的空间配置器的相关内容,可以查阅我的博客深入理解STL空间分配器(一)-CSDN博客、深入理解STL空间分配器(二)-CSDN博客、深入理解STL空间分配器(三)-CSDN博客、深入理解STL空间分配器(四)-CSDN博客。

3.用malloc和free

 C语言的传统方式分配和释放内存,代码如下:

    template <class T> struct CreateUsingMalloc{template <typename... Args>static T* Create(Args&&... args){void* p = std::malloc(sizeof(T));if (!p) return 0;return new(p) T(std::forward<Args>(args)...);}static void Destroy(T* p){p->~T();std::free(p);}};

4.静态内存分配

代码如下:

    template <class T> struct CreateStatic{#ifdef _MSC_VER
#pragma warning( push ) 
#pragma warning( disable : 4121 )
// alignment of a member was sensitive to packing
#endif // _MSC_VERunion MaxAlign{char t_[sizeof(T)];short int shortInt_;int int_;long int longInt_;float float_;double double_;long double longDouble_;struct Test;int Test::* pMember_;int (Test::*pMemberFn_)(int);};#ifdef _MSC_VER
#pragma warning( pop )
#endif // _MSC_VERtemplate <typename... Args>static T* Create(Args&&... args){static MaxAlign staticMemory_;return new(&staticMemory_) T(std::forward<Args>(args)...);}static void Destroy(T* p){p->~T();}};

上面的例子都用到了std::forward,实现了构造函数参数的完美转发,它的用法可以参考博客C++之std::forward-CSDN博客

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

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

相关文章

了解统计分类中的贝叶斯理论误差限

一、介绍 统计分类和机器学习领域正在不断发展&#xff0c;努力提高预测模型的准确性和效率。这些进步的核心在于一个基本基准&#xff0c;即贝叶斯理论误差极限。这个概念深深植根于概率和统计学&#xff0c;是理解分类算法的局限性和潜力的基石。本文深入探讨了贝叶斯错误率的…

【LabVIEW FPGA入门】使用LabVIEW FPGA进行编程并进行编译

在本文中会进行一个简单的FPGA编程演示&#xff0c;这通常可以验证编译工具链是否正常使用。在LabVIEW FPGA中和rt、PC编程一样使用数据流编程&#xff0c;但是需要注意的是FPGA中有些函数是不可以用的&#xff0c;因为这些函数很占用资源&#xff0c;且FPGA只能同时下载运行一…

AI软件开发:探索原理、挑战与未来趋势

AI软件开发已经成为当前最热门和具有前景的技术领域之一。随着人工智能技术的快速发展&#xff0c;AI软件的应用范围也在不断扩大。本文将主要探讨AI软件开发的原理、挑战以及未来的趋势。 首先&#xff0c;AI软件开发的原理是基于机器学习和深度学习算法。机器学习是一种通过…

Jetbrains ai assistant激活成功了

使用ai assistant插件助手 很完美&#xff0c;第一次用在idea 开发工具就完美的把激活了&#xff0c;你也不妨试试 链接地址&#xff1a;https://web.52shizhan.cn 激活后如下 登录页面 完美使用

python设计模式有哪几种

Python 中常见的设计模式有以下几种 一 单例模式&#xff08;Singleton Pattern&#xff09;&#xff1a;确保一个类只有一个实例&#xff0c;并提供全局访问点。 二 工厂模式&#xff08;Factory Pattern&#xff09;&#xff1a;使用工厂方法来创建对象&#xff0c;而不是直…

c++算法之枚举

目录 解空间的类型 循环枚举解空间 例题 特别数的和 输入格式 输出格式 输入样例&#xff1a; 输出样例&#xff1a; 解 例题 反倍数 问题描述 输入格式 输出格式 样例输入 样例输出 解 例题 找到最多的数 解 枚举算法是一种基本的算法思想&#xff0c;它通过…

喜报 | 联诚发斩获卓越品牌奖,总裁龙平芳荣获优秀企业家奖

1月10日&#xff0c;深圳市半导体产业发展促进会五届三次会员大会暨五届四次理/监事会在深圳宝安登喜路国际大酒店隆重举行&#xff0c;全体会员、党员、兄弟商协会等共600多位代表出席会议。联诚发LCF作为协会会长单位也受邀出席盛会。 本次大会颁布了卓越品牌奖、优秀企业奖、…

79LXX 三端负电源电压调节器,具有一系列固定电压输出,适用于小于100mA电源供给的场合

79LXX系列三端负电源电压调节器是单片双极型线性集成电路&#xff0c;采用TO92、SOT89-3的封装形式封装&#xff0c;有一系列固定的电压输出&#xff0c;适用于小于100mA电源供给的场合。 主要特点&#xff1a; 最大输出电流为100mA 固定输出电压分别为-5V、-6V、-8V、-9V、-1…

QT第三天

使用QT完成水果计价界面和功能&#xff0c;如下图&#xff1a; 运行结果&#xff1a; 代码&#xff1a; widget.h #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QListWidgetItem>QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_N…

redis复习总结

我的redis 1. redis集群 主从集群【哨兵集群】&#xff1a;主从集群是指中&#xff0c;存在一个master节点和多个slave节点。master节点负责接收客户端的读写&#xff0c;slave节点负责读操作。主节点一旦接收到数据的变更&#xff0c;就会将数据同步至slave节点。 但这样的…

用TF-IDF处理文本数据

计算机擅长处理数字&#xff0c;但不擅长处理文本数据&#xff0c;TF-IDF是处理文本数据最广泛使用的技术之一&#xff0c;本文对它的工作原理以及它的特性进行介绍。 根据直觉&#xff0c;我们认为在文本数据分析中出现频率更高的单词应该具有更大的权重&#xff0c;但事实并…

机器人技能学习-构建自己的数据集并进行训练

概要 若想训练自己的场景&#xff0c;数据集的重要性不做过多赘述&#xff0c;下面就基于 robomimic 和 robosuite 构建自己的数据集进行讲解&#xff0c;同时&#xff0c;也会附上 train 和 run 的流程&#xff0c;这样&#xff0c;就形成了闭环。 自建数据集 采集数据 采…

【MATLAB】REMD_LSTM神经网络时序预测算法

有意向获取代码&#xff0c;请转文末观看代码获取方式~也可转原文链接获取~ 1 基本定义 REMD-LSTM神经网络时序预测算法是一种结合了REMD&#xff08;Reservoir Enhanced Multi-scale Deep Learning&#xff09;算法和长短期记忆神经网络&#xff08;LSTM&#xff09;的时间序…

解决“Ubuntu系统与windows系统之间不能执行复制粘贴”之问题

在win11中&#xff0c;发现“Ubuntu系统与windows系统之间不能互相复制粘贴”&#xff0c;只能通过“FPT客户端FileZilla”才能交换文件&#xff0c;但遇到字符串&#xff0c;就没法实现了&#xff0c;因此&#xff0c;在两个系统之间实现互相复制和粘贴字符串&#xff0c;就很…

【Python数据可视化】matplotlib之绘制常用图形:折线图、柱状图(条形图)、饼图和直方图

文章传送门 Python 数据可视化matplotlib之绘制常用图形&#xff1a;折线图、柱状图&#xff08;条形图&#xff09;、饼图和直方图matplotlib之设置坐标&#xff1a;添加坐标轴名字、设置坐标范围、设置主次刻度、坐标轴文字旋转并标出坐标值matplotlib之增加图形内容&#x…

RK3568驱动指南|第十二篇 GPIO子系统-v

瑞芯微RK3568芯片是一款定位中高端的通用型SOC&#xff0c;采用22nm制程工艺&#xff0c;搭载一颗四核Cortex-A55处理器和Mali G52 2EE 图形处理器。RK3568 支持4K 解码和 1080P 编码&#xff0c;支持SATA/PCIE/USB3.0 外围接口。RK3568内置独立NPU&#xff0c;可用于轻量级人工…

Java医院智能3D导诊系统源码 微信小程序源码

医院智慧3D导诊系统&#xff0c; 通过输入疾病症状和选择部位进行导诊挂号&#xff0c;支持小程序端、APP端 开发背景 人们经常去医院因为不知道挂什么科而烦恼&#xff0c;有些病人不方便问又不好意思问。在互联网医院中挂号且又不知该挂什么科&#xff0c;找什么类型的医生&…

JavaScript的变量详解

一、变量的声明和赋值 编程中的程序其本质就是处理数据的过程&#xff0c;当输入指令时&#xff0c;就可以输出相应的内容&#xff0c;在输入和输出之间就是处理数据的过程。处理的数据可能有多种&#xff0c;多个&#xff0c;这时就需要使用不同的名字来存储、区分和提取不同的…

rime中州韵小狼毫 LaTex输入法配置

本文的分享一种在rime中州韵小狼毫须鼠管输入法中配置LaTex输入方案的方法&#xff0c;并不完美&#xff0c;仅供参考。 先睹为快 LaTex输入方案可以快捷的在公式模式下输入一些基础的数学公式&#xff0c;选词快捷&#xff0c;录入体验优良。 latex.schema.yaml latex.sc…

PMP学习考试经验总结

PMP备考日程计划表 我的PMP的备考大概花了三个月的时间, 可以分为以下几个阶段&#xff1a; Week 1-4: 读完PMBoK 前面7个知识领域&#xff08;中英文版PMBoK一起看&#xff09;。每看完一个知识领域&#xff0c;就看参考书里面的相应章节&#xff08;汪博士那本&#xff09;…