以下是关于 C++(UE4) 内存管理的一点简单分享
原始方式(Raw)
- malloc/free 是 C 中用于分配内存和释放内存的主要方式
- new/delete 是 C++ 中用于分配内存和释放内存的主要方式,除了内存管理之外, new/delete 还负责调用对象的构造函数和析构函数
- new[]/delete[] 是 new/delete 的数组形式
- 比较重要的一点是, new/delete 等内存管理的调用一定要匹配,譬如调用了 new 就一定要调用 delete(而不能 不调用 delete 或者调用 free 等不匹配的内存操作)
- new 运算符表达式基本分为两步操作,首先调用 operator new 函数分配内存,然后在该内存处调用对象的构造函数
- delete 运算符表达式基本也分为两步操作,首先调用对象的析构函数,然后调用 operator delete 函数释放对象的内存
- operator new 与 operator delete 可以定制重载
- UE4 进行了自己的重载工作(通过宏等方式)
- new 还有一些"变种"操作,譬如 placemenet new 等等,更多信息可以在这里找到
正常方式(Normal)
- 原始的内存管理方式存在很多问题,譬如逻辑控制上很难做到没有遗漏,而且让程序员人为的保证调用的匹配本身也非常困难
- 借助值语义对象的构造函数和析构函数可以帮助我们改善这个问题
- 这是一段代码示例,示例中通过 lock_guard 来保证 mutex 能正确的 lock 和 unlock(即使程序逻辑提前返回或者产生异常)
智能指针
- 将 RAII 的概念运用于 指针 上,便形成了智能指针的概念
- C++ 先前有 std::auto_ptr 这种智能指针,但在规范上却混淆了移动和复制语义,所以存在很多问题, C++17
已经将 std::auto_ptr 移除 - 目前 C++ 的智能指针分为: std::unique_ptr, std::shared_ptr 和 std::weak_ptr 这三种类型
- 智能指针中较常用的是 std::shared_ptr
- 关于 std::shared_ptr 有个相关的类型 std::enable_shared_from_this,这个类型的主要目的是为了解决复用 std::shared_ptr 时存在的重复释放问题
- std::enable_shared_from_this 示例代码
GC
- UE4 目前采用 Mark-Sweep 来进行 GC
- UE4 GC 适用于 UObject 类型, 对于非 UObject 类型,需要继承 FGCObject 类型
- UObject 不适用于 C++ 概念中的智能指针(但适用于 UE4 扩展的一些智能指针类型,譬如 TWeakObjectPtr 等等)
- UObject 需要借助一些方式来保持 GC 引用
结论
- 对于非 GC 类型,你可以直接使用原始方式来进行内存管理(消耗最小),但是你需要处理好相关的内存问题
- 但更一般的,还是建议你使用智能指针(譬如 std::shared_ptr) 来管理非 GC 类型
- 对于 GC(主要指 UObject) 类型,小心处理相关的引用关系
|