首页 > 系统相关 >C/C++内存管理

C/C++内存管理

时间:2024-08-16 19:22:27浏览次数:9  
标签:管理 int C++ 内存 operator new size delete

文章目录


前言

        C++ 的内存管理是程序设计中的一个关键部分,涉及到内存的分配、使用和释放。理解内存管理对于编写高效和稳定的C++程序至关重要

C/C++内存分布

    在C/C++程序中,内存的分布方式通常可以分为一下几个主要区域

  1. 代码段(Text Segment / Code Segment)
        存储程序的机器代码,即编译后的可执行代码
    特点:通常是只读的,以防止程序意外修改代码。对于某些系统,可以将代码段标记为只读,从而避免程序自修改
  2. 数据段(Data Segment)
  • 初始化数据段(Initialized Data Segment)
        存储已初始化的全局变量和静态变量
    特点:这些变量在程序启动时即分配内存,并在程序的整个生命周期内保持其分配
  • 未初始化数据段(BSS Segment)
        存储未初始化的全局变量和静态变量(在程序启动时被初始化为零)。
    特点:BSS段的内存只在运行时被分配,但初始值为零
  1. 堆(Heap)
        用于动态内存分配,即在程序运行时通过 malloc、calloc、realloc(C语言)或 new(C++) 分配的内存
    特点:堆的大小并不固定,可以动态增长或缩小;然而,堆内存的管理是程序员的责任,必须通过 free(C语言) 或 delete(C++) 释放不再使用的内存,以避免内存泄漏
  2. 栈(Stack)
        存储局部变量、函数参数和返回地址。每当一个函数被调用时,会为其分配一个栈帧,包含该函数的局部变量、参数以及返回地址
    特点:栈内存的分配和释放是自动的,随着函数的调用和返回而自动进行。栈的大小通常是有限的,因此过深的递归或过大的局部数组可能导致栈溢出
  3. 常量区(Literal Pool/Constant Segment)
        存储程序中的常量数据,如字符串常量和一些不可修改的变量, 一般位于正文代码段中
    特点:常量区通常是只读的,用于防止意外修改这些常量。
    进程地址空间

C语言内存管理

    我们先来回顾一下C语言的内存管理, 在C语言中,动态内存管理主要是通过几个内存管理函数完成的

malloc

向内存申请指定大小内存

#include <stdlib.h>
void *malloc(size_t size);

size : 需要申请的内存大小(字节)
申请内存成功返回一个指向这块空间的起始地址, 申请失败返回NULL

示例

int main()
{
    int size=255;
    int* arr=(int*)malloc(sizeof(int)*size);
    //...
    free(arr);
    return 0;
}

calloc

向内存申请指定大小内存, 并初始化为0

#include <stdlib.h>
void *calloc(size_t nmemb, size_t size);

nuemb : 数据的个数
size : 每个数据的大小
申请内存成功返回一个指向这块空间的起始地址, 申请失败返回NULL

示例

int main()
{
    int len=100;
    //等同于malloc(len*sizeof(char));
    char* str=(char*)calloc(len,sizeof(char));
    //...
    free(str);
    return 0;
}

realloc

控制已经申请的空间大小

#include <stdlib.h>
void *realloc(void *ptr, size_t size)

ptr : 指向要调整大小的内存块的指针
size : 新的内存块的大小
成功返回指向新内存块的指针,类型为 void*。如果调整失败,返回 NULL, 原内存块依然有效,未被释放

示例

int main()
{
    int* arr=(int*)malloc(10*sizeof(int));
    int *new_arr = (int *)realloc(arr, 20 * sizeof(int)); // 调整数组大小到20个整数
    if(new_arr!=NULL) arr=new_arr;
    return 0;
}

reallocarray

#include <stdlib.h>
void *reallocarray(void *ptr, size_t nmemb, size_t size);

ptr : 指向要调整大小的数组的指针。
nmemb : 表示新的数组元素的数量。
size : 表示每个元素的大小(字节)

与realloc几乎相同, reallocarray的不同之处在于它安全地处理nmemb和size的乘积

free

释放内存

#include <stdlib.h>
void free(void *ptr);

ptr : 要释放内存的起始地址

C++内存管理

    C语言内存管理方式在C++中可以继续使用,但有些地方就无能为力,而且使用起来比较麻烦,因
此C++又提出了自己的内存管理方式

new/delete

    C++使用new操作符来申请内存, delete操作符释放内存

内置类型

示例

int main()
{
  // 动态申请一个int类型的空间
  int* p1 = new int;
  
  // 动态申请一个int类型的空间并初始化为10
  int* p2 = new int(10);
  
  // 动态申请10个int类型的空间
  int* p3 = new int[10];

  delete ptr4;
  delete ptr5;
  delete[] ptr6;
  return 0;
}

注意 : new与delete, new[]与delete[]要匹配使用, 否则会出现未定义行为, 发生难以预料的后果

自定义类型

    new/delete 和 malloc/free最大区别是 new/delete对于【自定义类型】除了开空间还会调用构造函数和析构函数
示例

class A
{
public:
	A(int a = 0)
		: _a(a)
	{
		cout <<  this <<"->A()"<< endl;
	}
	~A()
	{
		cout << this<<"->~A()" << endl;
	}
private:
	int _a;
};

int main()
{
	SetConsoleOutputCP(CP_UTF8);
	cout << "malloc:";
	A* p1 = (A*)malloc(sizeof(A));
	cout << endl;
	cout << "new:";
	A* p2 = new A(1);
	cout << "free:";
	free(p1);
	cout << endl;
	cout << "delete:";
	delete p2;
	cout << "malloc申请数组:";
	A* p5 = (A*)malloc(sizeof(A) * 3);
	cout << endl;
	cout << "new[]申请数组";
	A* p6 = new A[3];
	cout << "free释放数组:";
	free(p5);
	cout << endl;
	cout << "delete释放数组:";
	delete[] p6;
	return 0;
}

执行结果

operator new/operator delete

    new和delete是用户进行动态内存申请和释放的操作符,operator new 和operator delete是系统提供的全局函数,new在底层调用operator new全局函数来申请空间,delete在底层通过operator delete全局函数来释放空间。

void* operator new(std::size_t size) throw(std::bad_alloc);

operator new只申请空间, 不调用构造函数, 底层调用malloc
区别
operator new 是一个函数,仅负责内存分配,可以被重载以提供自定义行为
new 是一个运算符,不仅分配内存,还调用构造函数来初始化对象

void operator delete(void* ptr) throw();

operator delete仅负责释放内存,而不会调用对象的析构函数, 底层调用free
区别
operator delete 是一个函数,仅负责内存的释放,可以被重载以提供自定义行为
delete 是一个运算符,它不仅释放内存,还负责调用对象的析构函数进行资源清理

定位new

    定位new表达式是在已分配的原始内存空间中调用构造函数初始化一个对象
使用格式 : new (ptr) type;
示例

class A
{
public:
	A(int a )
		: _num(a)
	{}
	~A()
	{
		cout << _num << endl;
	}
private:
	int _num;
};
int main()
{
	// p1现在指向的只不过是与A对象相同大小的一段空间,还不能算是一个对象,因为构造函数没有执行
	A* p1 = (A*)malloc(sizeof(A));
	new(p1)A(10);  // 定位new
	delete p1;
	return 0;
}

执行结果

内存泄漏

    内存泄漏指因为疏忽或错误造成程序未能释放已经不再使用的内存的情况。内存泄漏并不是指内存在物理上的消失,而是应用程序分配某段内存后,因为设计错误,失去了对该段内存的控制,因而造成了内存的浪费, 内存泄漏会导致响应越来越慢

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

标签:管理,int,C++,内存,operator,new,size,delete
From: https://blog.csdn.net/2301_77838258/article/details/141267523

相关文章

  • python-flask计算机毕业设计中医院信息管理系统(程序+开题+论文)
    文件加密系统的设计与实现tp835本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景随着中医药事业的蓬勃发展,中医院作为传承与发展中医药文化的重要载体,其日常运营管理的复杂性和高效性需求......
  • 数据结构(C++版)——顺序表
    一、顺序表有关的基本操作1、InitList(&L):初始化线性表,构造一个空的线性表L2、DestroyList(&L):销毁线性表L3、ClearList(&L):将线性表L重置为空表4、ListEmpty(L):若L为空表,则返回TURE,否则返回FALSE5、GetElem(L,i,&e):用e返回L中第i个数据元素的值6、LocateElem(L,e):在线性......
  • C++八股文——内存管理(堆和栈的区别? C++内存分区? 内存泄漏?如何避免?什么是智能指针?有哪
    文章目录C++内存管理堆和栈的区别C++内存分区内存泄漏?如何避免?1、什么是内存泄露?2、内存泄漏的分类3、什么操作会导致内存泄露?4、如何防⽌内存泄露?5、智能指针有了解哪些?6、构造函数,析构函数要设为虚函数吗,为什么?什么是智能指针?有哪些种类?new和malloc有什么区别?d......
  • 【源码+论文】springboot师生共评的作业管理系统设计与实现
    系统包含:源码+论文所用技术:SpringBoot+Vue+SSM+Mybatis+Mysql获取资料请私聊我2.2B/S结构B/S架构是一种基于互联网系统的软件系统开发架构,是现如今在软件系统开发中采用非常大量的一种软件系统结构。现如今B/S架构已经被大量使用,打破了C/S结构的结构,给基于网络结构的软件......
  • 【源码+论文】基于springboot的课程作业管理系统
    系统包含:源码+论文所用技术:SpringBoot+Vue+SSM+Mybatis+Mysql获取资料请私聊我Java就像C语言、C#语言等,也是一种程序开发语言,而它的特点就是面向对象。作为一种程序开发与设计的语言,它有很多特性,主要特性就是面向对象、夸平台以及可以分布式运行。Java语言项目不但安全性高......
  • 2024.8.15(python管理mysql、Mycat实现读写分离)
    一、python管理mysql1、搭建主mysql[root@mysql57~]#tar-xfmysql-5.7.44-linux-glibc2.12-x86_64.tar.gz [root@mysql57~]#cp-rmysql-5.7.44-linux-glibc2.12-x86_64/usr/local/mysql[root@mysql57~]#rm-rf/etc/my.cnf[root@mysql57~]#mkdir/usr/local/......
  • java+vue计算机毕设基于web的电竞社信息管理系统的设计与实现【源码+开题+论文】
    本系统(程序+源码)带文档lw万字以上文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容研究背景随着电子竞技产业的迅猛发展,电竞社作为连接电竞爱好者与赛事活动的桥梁,其重要性日益凸显。然而,传统的管理方式往往依赖于人工记录与沟通,不仅效率低下,......
  • python管理MySQL数据库 mysql5.7读写分离 配置mycat(twenty-nine day)
    一、pymysql管理数据库1、搭建主mysql5.7[root@mysql57~]#lsanaconda-ks.cfg mysql-5.7.44-linux-glibc2.12-x86_64.tar.gz[root@mysql57~]#tar-xfmysql-5.7.44-linux-glibc2.12-x86_64.tar.gz [root@mysql57~]#lsanaconda-ks.cfgmysql-5.7.44-linux-glibc2......
  • C++智能指针讨论
    一段有问题的代码。#include<iostream>intmain(){for(inti=0;i<10000000;i++){double*p=newdouble(1);}return0;}这里就有了内存泄漏。修改为下边的代码,是可以的,但是会比较占用CPU资源。#include<iostream>intmain()......
  • EasyCVR视频汇聚平台:打造全栈视频监控系统的基石,解锁可视化管理与高效运维
    随着科技的飞速发展,视频监控已成为现代社会不可或缺的一部分,广泛应用于社区、公共场所、工业领域等多个场景。EasyCVR视频汇聚平台,作为一款高性能的视频汇聚管理平台,凭借其强大的视频处理、汇聚与融合能力,在构建全栈视频监控系统中展现出了独特的优势。本文将深入探讨EasyCVR视频......