C++内存分配方式

news/2025/3/21 20:22:20/

文章目录

  • 1、静态内存分配
  • 2、栈内存分配
  • 3、堆内存分配
  • 4、内存池分配
  • 5、placement new
      • 语法
      • 工作原理
      • 示例
    • `placement new`
      • 应用场景

在C++ 中,内存分配主要有以下几种方式:

1、静态内存分配

  • 特点:在编译时就确定了内存的分配和释放,内存空间是在程序运行前就被预留好的,程序结束时由系统自动释放。
  • 示例:全局变量、静态局部变量都属于静态内存分配。
#include <iostream>// 全局变量,位于静态存储区
int globalVar = 10;void func() {// 静态局部变量,位于静态存储区static int staticVar = 20;staticVar++;std::cout << "Static variable value: " << staticVar << std::endl;
}int main() {std::cout << "Global variable value: " << globalVar << std::endl;for (int i = 0; i < 5; i++) {func();}return 0;
}

2、栈内存分配

  • 特点:由编译器自动分配和释放,用于存储函数的参数、局部变量等。其分配和释放速度快,遵循后进先出(LIFO)的原则。但栈的空间大小有限,通常在几KB到几MB之间,如果分配的空间超过栈的大小,就会导致栈溢出。
  • 示例
#include <iostream>void func() {// 局部变量,在栈上分配内存int localVar = 30;std::cout << "Local variable value: " << localVar << std::endl;
}int main() {func();return 0;
}

3、堆内存分配

  • 特点:由程序员手动分配和释放,使用 new 操作符进行内存分配,使用 delete 操作符释放内存。堆内存的大小只受限于系统的虚拟内存大小,相对来说空间比较灵活,但分配和释放的速度比栈内存慢,且如果程序员忘记释放内存,会导致内存泄漏。
  • 示例
#include <iostream>int main() {// 在堆上分配一个整数的内存空间int* heapVar = new int;*heapVar = 40;std::cout << "Heap variable value: " << *heapVar << std::endl;// 释放堆内存delete heapVar;return 0;
}

4、内存池分配

  • 特点:是一种预先分配一定大小内存块的技术,程序在运行过程中需要内存时,直接从内存池中获取,而不是每次都进行系统级的内存分配操作。当使用完内存后,将其归还到内存池中,而不是立即释放回系统。这样可以减少频繁的内存分配和释放操作带来的开销,提高程序的性能和效率,尤其对于大量小对象的频繁分配和释放场景效果显著。
  • 示例:以下是一个简单的内存池示例代码,实现了一个基本的内存池类,用于分配和释放固定大小的内存块。
#include <iostream>
#include <vector>class MemoryPool {
public:MemoryPool(size_t blockSize, size_t numBlocks) : blockSize(blockSize) {// 分配内存池的总大小char* pool = new char[blockSize * numBlocks];// 将每个内存块的地址加入到可用列表中for (size_t i = 0; i < numBlocks; i++) {freeBlocks.push_back(pool + i * blockSize);}}~MemoryPool() {// 释放内存池的内存delete[] freeBlocks[0];}void* allocate() {if (freeBlocks.empty()) {std::cerr << "Memory pool exhausted." << std::endl;return nullptr;}// 从可用列表中取出一个内存块void* block = freeBlocks.back();freeBlocks.pop_back();return block;}void deallocate(void* block) {// 将内存块归还到可用列表中freeBlocks.push_back(static_cast<char*>(block));}private:// 可用内存块的列表std::vector<char*> freeBlocks;size_t blockSize;
};int main() {// 创建一个内存池,每个内存块大小为16字节,共10个内存块MemoryPool pool(16, 10);// 从内存池中分配内存void* block1 = pool.allocate();void* block2 = pool.allocate();// 使用内存块...// 释放内存块回内存池pool.deallocate(block1);pool.deallocate(block2);return 0;
}

5、placement new

是C++ 中的一种特殊的内存分配方式,它允许在已分配的内存空间上构造对象。以下是关于placement new的详细介绍:

语法

placement new的语法形式为:new (place_address) type (initializers);,其中place_address是一个指向已分配内存的指针,type是要构造的对象类型,initializers是可选的构造函数参数列表。

工作原理

  • placement new不会分配新的内存,而是在给定的地址上直接构造对象。它假定所提供的内存已经足够大,能够容纳要构造的对象,并且该内存未被其他对象占用。
  • 当使用placement new时,编译器会调用对象的构造函数来初始化对象,但不会调用operator new来分配内存。

示例

下面是一个简单的示例,展示了placement new的用法:

#include <iostream>
#include <new>class MyClass {
public:MyClass() { std::cout << "MyClass constructor called" << std::endl; }~MyClass() { std::cout << "MyClass destructor called" << std::endl; }
};int main() {// 分配一块足够大的内存void* buffer = operator new(sizeof(MyClass));// 使用placement new在分配的内存上构造对象MyClass* obj = new (buffer) MyClass();// 使用obj// 手动调用析构函数obj->~MyClass();// 释放内存operator delete(buffer);return 0;
}

placement new

应用场景

  • 内存池管理:在内存池实现中,预先分配一大块内存,然后使用placement new在内存池中分配和构造对象,避免频繁地调用newdelete导致的内存碎片和性能开销。
  • 对象数组的构造:可以分配一个连续的内存块来存储对象数组,然后使用placement new逐个构造数组中的对象。
  • 嵌入对象到特定内存位置:某些情况下,可能需要将对象放置在特定的内存地址,例如与硬件设备交互或遵循特定的内存布局要求,placement new可以满足这种需求。

需要注意的是,使用placement new时,开发者需要负责确保所提供的内存是合适的,并且在对象不再使用时,要手动调用析构函数来释放资源,以避免内存泄漏和未定义行为。


http://www.ppmy.cn/news/1580961.html

相关文章

qml中ComboBox组件onCurrentIndexChanged与onActivated的使用

在qml页面中使用ComboBox时&#xff0c;一般会有以下用法&#xff1a; ComboBox{id: boxmodel: yourBindingModelonCurrentIndexChanged: { //业务代码} } 通常不会有什么问题&#xff0c;切换下拉列表时触发onCurrentIndexChanged&#xff0c;然后执行业务代码。 但是&am…

MATLAB语法速成-对照C语言学习

一、变量与数据类型 变量声明&#xff1a;MATLAB 是动态类型语言&#xff0c;无需提前声明变量类型。例如&#xff1a; a 5; % 定义一个整数变量 b 3.14; % 定义一个浮点数变量 c Hello; % 定义一个字符串变量数据类型&#xff1a;常见的数据类型有数值类型&#xff08;整…

jvm中每个类的Class对象是唯一的吗

jvm中每个类的Class对象是唯一的吗 在 Java 中&#xff0c;同一个类的 Class 对象在由同一个类加载器加载时是唯一的。析&#xff1a; 1. 同一类加载器的唯一性 规则&#xff1a;若一个类被同一个类加载器加载&#xff0c;无论创建多少实例&#xff0c;其 Class 对象始终唯一…

Redis Sentinel(哨兵模式)高可用性解决方案

一、概述 Redis Sentinel&#xff08;哨兵模式&#xff09;是Redis的高可用性&#xff08;High Availability, HA&#xff09;解决方案&#xff0c;它通过哨兵系统和Redis实例的协同工作&#xff0c;确保了Redis服务的高可用性和数据的持久性。哨兵系统由一个或多个哨兵进程组…

当前企业使用VPN面临的不足和挑战

VPN的防护理念无法满足数字化转型的需求 古人云&#xff1a;知己知彼&#xff0c;百战不殆&#xff0c;既然要替换VPN&#xff0c;就要先了解VPN。VPN于1996年起源&#xff0c;98年首次在我国出现&#xff0c;历经25年的持续演进&#xff0c;直到现在依然广泛流行。VPN的起源背…

Pot-App 本地deepseek-r1 翻译开源插件,支持本地ollama deepseek-r1系列模型,同时在POT翻译窗口不显示模型思考过程

一、软件介绍 文末提供插件及源码下载 此开源插件作為支持本地ollama deepseek-r1系列模型&#xff0c;並在POT输出窗口中不显示模型思考过程。 模型安装&#xff08;根据自己的电脑配置安装相应版本&#xff0c;支持官方1.5b~8b&#xff09; Ollama模型网址&#xff1a;deep…

php的用途和基础语法【初学者进】

PHP 是一种非常流行的服务器端脚本语言&#xff0c;主要用于开发动态网站和 Web 应用程序。 一、PHP 的用途 开发动态网站 动态网站的内容可以根据用户的需求实时生成。比如&#xff0c;当你在电商网站上搜索商品时&#xff0c;网站会根据你的搜索关键词动态显示相关商品信息…

网络爬虫简介(大白话)

用大白话讲网络爬虫 一、网络爬虫是啥&#xff1f;能干啥&#xff1f; 简单说&#xff0c;网络爬虫就是个自动上网搜资料的机器人。 比如你想知道全网哪家奶茶店最便宜&#xff0c;自己一家家查太费劲&#xff0c;爬虫就能帮你自动翻遍所有外卖平台&#xff0c;把价格和评分全…