侯捷 C++ 课程学习笔记:学习侯捷课程后对 C++ 内存分配的新认知

目录

学习前对内存分配的常规认知

侯捷课程中的关键知识点

堆内存与栈内存分配机制

智能指针在内存分配中的应用

内存池技术

内存对齐与优化

内存分配在实际项目中的影响与优化

游戏开发项目中的内存管理

数据处理程序中的内存优化


在接触侯捷老师的 C++ 课程之前,我对 C++ 内存分配的理解基本停留在使用new和delete进行动态内存分配与释放的常规操作上。对于内存分配背后复杂的机制、不同内存区域的特性以及如何优化内存使用,缺乏深入的认识。随着课程学习的逐步深入,我对 C++ 内存分配有了全新且全面的理解,这极大地影响了我在实际编程中的内存管理策略。

学习前对内存分配的常规认知

在以往的编程实践中,当需要动态创建对象或数组时,我通常使用new运算符,例如:

 

int* dynamicArray = new int[10];

for (int i = 0; i < 10; ++i) {

dynamicArray[i] = i;

}

// 使用完后记得释放内存

delete[] dynamicArray;

对于简单的程序,这种方式能够满足基本的内存需求。但我并没有过多思考内存是从哪里分配的,以及分配和释放内存的效率问题。在处理复杂数据结构或大型项目时,这种浅层次的认知导致我在内存管理方面遇到了诸多问题,如内存泄漏、频繁的内存碎片等。

侯捷课程中的关键知识点

堆内存与栈内存分配机制

侯捷老师在课程中详细讲解了 C++ 中堆内存和栈内存的分配机制。栈内存由编译器自动管理,用于存储局部变量、函数参数等。当函数被调用时,其局部变量在栈上分配内存,函数结束时,这些内存自动被释放。例如:

 

void function() {

int localVar = 10; // localVar存储在栈上

} // 函数结束,localVar的内存自动释放

而堆内存则需要程序员手动管理,通过new和delete(或malloc和free)来分配和释放。堆内存的分配相对灵活,但也容易出现内存管理问题。例如,在使用new分配内存时,可能会因为内存不足而导致分配失败,此时需要进行错误处理:

 

int* ptr = nullptr;

try {

ptr = new int;

} catch (const std::bad_alloc& e) {

std::cerr << "Memory allocation failed: " << e.what() << std::endl;

}

if (ptr) {

*ptr = 20;

delete ptr;

}

智能指针在内存分配中的应用

课程中着重强调了智能指针在内存分配管理中的重要作用。智能指针,如std::unique_ptr、std::shared_ptr和std::weak_ptr,能够自动管理所指向对象的生命周期,有效避免内存泄漏。以std::unique_ptr为例,它独占所指向对象的所有权,当std::unique_ptr离开其作用域时,会自动释放所指向的对象:

 

#include <memory>

void process() {

std::unique_ptr<int> uniquePtr(new int(30));

// 对uniquePtr所指向的对象进行操作

} // uniquePtr离开作用域,所指向的int对象自动释放

std::shared_ptr允许多个指针共享同一对象的所有权,通过引用计数来管理对象的生命周期。当引用计数降为 0 时,对象自动被释放:

 

#include <memory>

int main() {

std::shared_ptr<int> sharedPtr1(new int(40));

std::shared_ptr<int> sharedPtr2 = sharedPtr1; // 引用计数增加

return 0;

} // sharedPtr1和sharedPtr2离开作用域,引用计数降为0,对象被释放

内存池技术

侯捷老师还介绍了内存池技术,这是一种优化内存分配的有效方法。内存池预先分配一块较大的内存区域,当程序需要分配小内存块时,直接从内存池中获取,而不是每次都向操作系统申请内存。当内存块使用完毕后,再将其归还到内存池中。这种方式减少了频繁的系统调用,提高了内存分配的效率,同时也减少了内存碎片的产生。例如,在一个频繁创建和销毁小对象的程序中,使用内存池可以显著提升性能:

 

class MemoryPool {

private:

char* pool;

size_t poolSize;

size_t blockSize;

char* nextBlock;

public:

MemoryPool(size_t size, size_t block) : poolSize(size), blockSize(block) {

pool = new char[poolSize];

nextBlock = pool;

}

void* allocate() {

if (nextBlock + blockSize > pool + poolSize) {

return nullptr; // 内存池耗尽

}

void* result = nextBlock;

nextBlock += blockSize;

return result;

}

~MemoryPool() {

delete[] pool;

}

};

内存对齐与优化

内存对齐也是课程中的一个重要知识点。编译器为了提高内存访问效率,会按照一定规则对数据进行对齐存储。不同类型的数据在内存中的起始地址需要满足特定的对齐要求,通常是该数据类型大小的整数倍。例如,对于一个包含不同类型成员的结构体:

 

struct MyStruct {

char a;

int b;

short c;

};

在某些编译器下,MyStruct的大小可能并不是简单的1 + 4 + 2 = 7字节,而是会根据对齐规则进行填充,实际大小可能为 8 字节或 12 字节。了解内存对齐规则,有助于在设计数据结构时,合理安排成员顺序,减少内存浪费,提高内存访问效率。

内存分配在实际项目中的影响与优化

游戏开发项目中的内存管理

在一个 2D 游戏开发项目中,需要频繁地创建和销毁游戏对象,如角色、道具、场景元素等。最初,使用普通的new和delete进行内存分配和释放,随着游戏对象数量的增加,性能问题逐渐显现。游戏出现卡顿现象,帧率不稳定。通过学习课程中的内存管理知识,引入智能指针来管理游戏对象的生命周期,避免了内存泄漏。同时,采用内存池技术来分配小对象,如游戏中的子弹、粒子效果等。这大大提高了内存分配的效率,减少了内存碎片,游戏的性能得到了显著提升,运行更加流畅。

数据处理程序中的内存优化

在一个处理大量金融数据的程序中,需要频繁地读取、处理和存储数据。数据以不同的数据结构进行组织,如数组、链表、树等。在这个过程中,合理的内存分配和管理至关重要。通过分析数据的访问模式和生命周期,对于频繁访问且生命周期较长的数据,使用静态内存分配或内存池进行管理,减少内存分配和释放的开销。对于临时数据,使用栈内存或智能指针进行管理。同时,注意数据结构的设计,遵循内存对齐规则,提高内存访问效率。这些优化措施使得数据处理程序的运行速度大幅提升,能够更快地处理海量金融数据。

通过学习侯捷老师的课程,我对 C++ 内存分配有了全面且深入的理解。在今后的编程实践中,我将充分运用所学的内存分配知识,根据不同的应用场景选择合适的内存分配方式,优化内存使用,避免内存相关的问题,提高程序的性能和稳定性,为开发高质量的 C++ 项目奠定坚实的基础。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值