文章

C++跟踪内存分配

重写 new 和 delete 操作符

我们知道一个 class 的 new 是分为三步:operator new(其内部调用 malloc)返回 void*static_cast 转换为这个对象指针、构造函数。而 delete 则分为两步:构造函数、operator delete

new 和 delete 都是表达式,是不能重载的;而把他们行为往下分解则是有 operator new 和 operator delete,是有区别的。

直接用的表达式的行为是不能变的,不能重载的,即 new 分解成上图的三步与 delete 分解成上图的两步是不能重载的。这里内部的 operator new 和 operator delete 底层其实是调用的 malloc,这些内部的几步则是可以重载的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <iostream>

// 写这个函数就是说不要用standard library的operator new
// 链接器实际上就会改为链接这个函数
void* operator new(size_t size)
{
	std::cout << "Allocing " << size << " bytes\n";
	return malloc(size);
}

void operator delete(void* memory, size_t size)
{
	std::cout << "Free " << size << " bytes\n";
	free(memory);
}

struct Entity
{
	int x, y, z;
};
 
int main()
{
	{
		std::string name = "hbh";
	}
	Entity* e = new Entity();
	delete e;

	std::cin.get();
}

还可以写一个简单统计内存分配的类,在每次 new 的时候统计分配内存,在每次 delete 时统计释放内存,可计算出已经分配的总内存:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
// 重写new、free操作符之后就能方便地跟踪内存分配了(加断点)

#include <iostream>
#include <memory>

struct AllocationMetrics
{
    uint32_t TotalAllocated = 0; //总分配内存
    uint32_t TotalFreed = 0; //总释放内存

    uint32_t CurrentUsage() { return TotalAllocated - TotalFreed; } //写一个小函数来输出 当前用了多少内存
};

static AllocationMetrics s_AllocationMetrics; //创建一个全局静态实例

void *operator new(size_t size)
{
    s_AllocationMetrics.TotalAllocated += size; //在每一个new里计算总共分配了多少内存
    // std::cout << "Allocate " << size << " bytes.\n";
    return malloc(size);
}

void operator delete(void *memory, size_t size)
{
    s_AllocationMetrics.TotalFreed += size;
    // std::cout << "Free " << size << " bytes.\n";
    free(memory);
}

struct Object
{
    int x, y, z;
};
//可以用一个函数输出我们的内存使用情况
static void PrintMemoryUsage()
{
    std::cout << "Memory Usage:" << s_AllocationMetrics.CurrentUsage() << " bytes\n";
}

int main()
{
    PrintMemoryUsage();
    {
        std::unique_ptr<Object> obj = std::make_unique<Object>();
        PrintMemoryUsage();
    }

    PrintMemoryUsage();
    Object *obj = new Object;
    PrintMemoryUsage();
    delete obj;
    PrintMemoryUsage();
    std::string string = "Cherno";
    PrintMemoryUsage();

    return 0;
}
本文由作者按照 CC BY 4.0 进行授权