2

Electronic Arts EASTLeast::allocator要求用户实现一个特殊的new运算符(如本示例所示)。该new操作符有一个const char* name,它应该用于记录有关执行 EASTL 容器的内存分配的应用程序特定信息。EASTL最佳实践指南还提到应该“命名容器以跟踪内存使用情况” 。

但是,似乎没有任何对应const char* name的 pass by eastl::allocator::deallocate,因此似乎没有内置的方法来记录内存释放

打算如何使用这个 EASTL 调试功能?我想我一定错过了什么。一位 EA 软件工程师在 2015 年也做了一个相关的演讲,他展示了 EA 开发的一些用于内存调试的内部工具,似乎建议他们跟踪分配和释放(例如,确保“游戏级别”的内存1”在“游戏级别 2”开始时被释放)。

4

1 回答 1

1

EASTL 的分配器是有状态的并且绑定到容器的实例上;意味着它们是在实例级别定义的:

EASTL 所做的是使用一种更熟悉的内存分配模式,即只有一个分配器类接口,它被所有容器使用。此外,EASTL 容器允许您访问它们的分配器并查询它们、命名它们、更改它们等。

EASTL 选择在容器交换和分配操作期间使分配器不会在容器之间复制。这意味着如果容器 A 与容器 B 交换其内容,则两个容器都保留其原始分配器。类似地,将容器 A 分配给容器 B 会导致容器 B 保留其原始分配器。等效的容器应通过 operator==; 报告。如果分配器相等,EASTL 将进行智能交换,否则将进行暴力交换。

来自https://github.com/questor/eastl/blob/master/doc/EASTL%20Design.html

所以我会在分配器类中添加一个成员并跟踪其中的内存计数,如下所示:

#ifndef EASTL_CUSTOM_ALLOCATOR_H_
#define EASTL_CUSTOM_ALLOCATOR_H_

#include "new_implementation.hpp"
#include <EASTL/list.h>
#include <iostream>

#define DEBUG_MACRO

class EASTL_CustomAllocator {
public:
    EASTL_CustomAllocator(const char* pName = EASTL_NAME_VAL(EASTL_ALLOCATOR_DEFAULT_NAME))
        : m_pName(pName), m_totalAmountOfBytesAllocated(0) {
#ifdef DEBUG_MACRO
        std::cout << m_pName << ": default construct allocator" << std::endl;
#endif
    }
    EASTL_CustomAllocator(const EASTL_CustomAllocator& x)
        : m_pName(x.m_pName),
          m_totalAmountOfBytesAllocated(x.m_totalAmountOfBytesAllocated) {
#ifdef DEBUG_MACRO
        std::cout << m_pName << ": copy construct allocator" << std::endl;
#endif
    }
    EASTL_CustomAllocator(const EASTL_CustomAllocator& x, const char* pName)
        : m_pName(pName),
          m_totalAmountOfBytesAllocated(x.m_totalAmountOfBytesAllocated) {
#ifdef DEBUG_MACRO
        std::cout << m_pName << ": copy construct allocator" << std::endl;
#endif
    }

    EASTL_CustomAllocator& operator=(const EASTL_CustomAllocator& x) {
#ifdef DEBUG_MACRO
        std::cout << m_pName << ": copy assignment" << std::endl;
#endif
        m_pName = x.m_pName;
        m_totalAmountOfBytesAllocated = x.m_totalAmountOfBytesAllocated;
        return *this;
    }

    void* allocate(size_t num_of_bytes, int flags = 0) {
        m_totalAmountOfBytesAllocated += num_of_bytes;
        void* p = ::new((char*)0, flags, 0, (char*)0,        0) char[num_of_bytes];
#ifdef DEBUG_MACRO
        std::cout << m_pName << ": allocate " << num_of_bytes << " bytes" << " at: " << (void*) p << std::endl;
#endif
        return p;
    }
    void* allocate(size_t num_of_bytes, size_t alignment, size_t offset, int flags = 0) {
        m_totalAmountOfBytesAllocated += num_of_bytes;
        void* p = ::new(alignment, offset, (char*)0, flags, 0, (char*)0,        0) char[num_of_bytes];
#ifdef DEBUG_MACRO
        std::cout << m_pName << ": allocate " << num_of_bytes << " bytes" << " at: " << (void*) p << std::endl;
#endif
        return p;
    }
    void  deallocate(void* p, size_t num_of_bytes) {
        m_totalAmountOfBytesAllocated -= num_of_bytes;
#ifdef DEBUG_MACRO
        std::cout << m_pName << ": deallocate " << num_of_bytes << " bytes" << " at: " << (void*) p << std::endl;
#endif
        delete[](char*)p;
    }

    const char* get_name() const {
        return m_pName;
    }
    void        set_name(const char* pName) {
        m_pName = pName;
    }
    size_t get_totalAmountOfBytesAllocated() const {
        return m_totalAmountOfBytesAllocated;
    }

protected:
    const char* m_pName;    // Debug name, used to track memory.
    size_t m_totalAmountOfBytesAllocated;   // keeps track of the memory currently allocated
};


bool operator==(const EASTL_CustomAllocator& a, const EASTL_CustomAllocator& b) {
    if (&a == &b) {
        return true;    // allocator a and b are equal if they are the same
    }
    else {
        return false;   // otherwhise, return false, because the state m_totalAmountOfBytesAllocated needs to be increased/decreased on splice and swap
    }
}
bool operator!=(const EASTL_CustomAllocator& a, const EASTL_CustomAllocator& b) {
    return false;
}


#endif /* EASTL_CUSTOM_ALLOCATOR_H_ */

将该自定义分配器类型作为模板参数传递给如下所示的东部容器(您也可以在构造时设置具有用户定义名称的实例,甚至稍后通过 set_allocator() 设置):

eastl::list<int, EASTL_CustomAllocator> 
list(EASTL_CustomAllocator("EASTL Some Name"));

但我不确定如何使用调试功能。

于 2017-09-18T11:51:10.367 回答