[toc]
介绍
内存分配模块在imgui.h中定义, 包含以下主要函数:
- IM_MALLOC()
- IM_FREE()
- IM_NEW()
- IM_PLACEMENT_NEW()
- IM_DELETE()
struct ImNewDummy {};
inline void* operator new(size_t, ImNewDummy, void* ptr) { return ptr; }
inline void operator delete(void*, ImNewDummy, void*) {} // This is only required so we can use the symmetrical new()
#define IM_ALLOC(_SIZE) ImGui::MemAlloc(_SIZE)
#define IM_FREE(_PTR) ImGui::MemFree(_PTR)
#define IM_NEW(_TYPE) new(ImNewDummy(), ImGui::MemAlloc(sizeof(_TYPE))) _TYPE
template<typename T> void IM_DELETE(T* p) { if (p) { p->~T(); ImGui::MemFree(p); } }
如上,ImGui 通过重载new函数,重新定义new的使用方式, 并以此追踪内存泄漏问题。
- IM_NEW、IM_FREE函数成对使用
- IM_PLACEMENT_NEW 在一个已分配内存的地方进行对象创建
- IM_DELETE 清理一个对象
内存分配结构剖析
C++ 中默认的new函数
_Ret_notnull_ _Post_writable_byte_size_(_Size)
_VCRT_ALLOCATOR void* __CRTDECL operator new(
size_t _Size
);
_Ret_maybenull_ _Success_(return != NULL) _Post_writable_byte_size_(_Size)
_VCRT_ALLOCATOR void* __CRTDECL operator new(
size_t _Size,
std::nothrow_t const&
) noexcept;
_Ret_notnull_ _Post_writable_byte_size_(_Size)
_VCRT_ALLOCATOR void* __CRTDECL operator new[](
size_t _Size
);
_Ret_maybenull_ _Success_(return != NULL) _Post_writable_byte_size_(_Size)
_VCRT_ALLOCATOR void* __CRTDECL operator new[](
size_t _Size,
std::nothrow_t const&
) noexcept;
因此, 不允许重载这个版本
void* operator new(size_t, void*);
所以, 增加一个ImNewDummy参数来规避此问题,如下:
#define IM_NEW(_TYPE) new(ImNewDummy(), ImGui::MemAlloc(sizeof(_TYPE))) _TYPE
同时, 在MemAlloc函数中, 我们可以统计内存分配大小、追踪内存泄漏等问题
void* ImGui::MemAlloc(size_t size)
{
cout << "call MemAlloc " << size << endl;
return GImAllocatorAllocFunc(size, GImAllocatorUserData);
}
void ImGui::MemFree(void* ptr)
{
cout << "call MemFree " << endl;
return GImAllocatorFreeFunc(ptr, GImAllocatorUserData);
}
真正的内存分配函数是由GImAllocatorAllocFunc来决定, GImAllocatorUserData是一个用户内存统计数据, 暂时没有什么需要注意的地方
static void* (*GImAllocatorAllocFunc)(size_t size, void* user_data) = MallocWrapper;
static void(*GImAllocatorFreeFunc)(void* ptr, void* user_data) = FreeWrapper;
// 记录分配相关的数据
static void* GImAllocatorUserData = NULL;
如上, 我们可以看到, GImAllocatorAllocFunc和GImAllocatorFreeFunc都是函数指针, 指向一个默认的分配器和释放器
// Used to silence "unused variable warnings". Often useful as asserts may be stripped out from final builds.
#define IM_UNUSED(_VAR) ((void)_VAR)
static void* MallocWrapper(size_t size, void* user_data) { IM_UNUSED(user_data); return malloc(size); }
static void FreeWrapper(void* ptr, void* user_data) { IM_UNUSED(user_data); free(ptr); }
其实, 最终就是我们熟悉的malloc函数。
IM_PLACEMENT_NEW
通俗点说,此函数就是在已有的内存空间上重新构造一个相同类型的对象
Person* p2 = IM_NEW(Person)();
Person* p3 = IM_PLACEMENT_NEW(p2) Person(1001, "李四");
内存地址:
模板函数IM_DELETE 和 IM_FREE区别
区别如下:
- IM_FREE 仅回收内存
- IM_DELETE 调用析构函数 && 内存回收
因此, 建议使用IM_DELETE函数
完整测试代码
#include<iostream>
#include<string>
using namespace std;
// Used to silence "unused variable warnings". Often useful as asserts may be stripped out from final builds.
#define IM_UNUSED(_VAR) ((void)_VAR)
static void* MallocWrapper(size_t size, void* user_data) { IM_UNUSED(user_data); return malloc(size); }
static void FreeWrapper(void* ptr, void* user_data) { IM_UNUSED(user_data); free(ptr); }
static void* (*GImAllocatorAllocFunc)(size_t size, void* user_data) = MallocWrapper;
static void(*GImAllocatorFreeFunc)(void* ptr, void* user_data) = FreeWrapper;
// 记录分配相关的数据
static void* GImAllocatorUserData = NULL;
namespace ImGui
{
void* MemAlloc(size_t size);
void MemFree(void* ptr);
}
void* ImGui::MemAlloc(size_t size)
{
cout << "call MemAlloc " << size << endl;
return GImAllocatorAllocFunc(size, GImAllocatorUserData);
}
void ImGui::MemFree(void* ptr)
{
cout << "call MemFree " << endl;
return GImAllocatorFreeFunc(ptr, GImAllocatorUserData);
}
struct ImNewDummy {};
// void* operator new(size_t, void*); // C++中, 不允许重新定义这个版本
inline void* operator new(size_t, ImNewDummy, void* ptr) { return ptr; }
inline void operator delete(void*, ImNewDummy, void*) {} // This is only required so we can use the symmetrical new()
#define IM_ALLOC(_SIZE) ImGui::MemAlloc(_SIZE)
#define IM_FREE(_PTR) ImGui::MemFree(_PTR)
#define IM_NEW(_TYPE) new(ImNewDummy(), ImGui::MemAlloc(sizeof(_TYPE))) _TYPE
#define IM_PLACEMENT_NEW(_PTR) new(ImNewDummy(), _PTR)
template<typename T> void IM_DELETE(T* p) { if (p) { p->~T(); ImGui::MemFree(p); } }
class Person {
public:
Person();
Person(int id, string name);
~Person();
int Id; //4
string name; // 28
void printInfo();
};
Person::Person()
{
this->Id = 0;
this->name = "";
}
Person::Person(int id, string name)
{
this->Id = id;
this->name = name;
}
Person::~Person()
{
cout << "call destructor func... " << endl;
}
void Person::printInfo()
{
cout << "the person's id is " << this->Id << this->name << endl;
}
void main()
{
// test 1 - new 和 free
//Person* p1 = new Person(1000, "张三");
//p1->printInfo();
//free(p1);
// test 2 - IM_NEW 和 IM_FREE
/*Person* p1 = IM_NEW(Person)(1000, "张三");
p1->printInfo();
IM_FREE(p1);*/
// test 3 - IM_NEW 和 IM_PLACEMENT_NEW
Person* p2 = IM_NEW(Person)();
Person* p3 = IM_PLACEMENT_NEW(p2) Person(1001, "李四");
// test 4 - 多次FREE
// IM_FREE 仅回收内存
//IM_FREE(p2);
//IM_FREE(p2);
// test 5 - IM_DELETE
// IM_DELETE 调用析构函数 && 内存回收
IM_DELETE(p2);
}