我用一个分配器替换了标准分配器,该分配器会“打电话通知”它消耗了多少内存。现在我正在检查我的一些代码,想知道为什么它分配然后释放这么多条目。
仅供引用,我并不是想预先优化我的代码或任何东西,我主要是好奇,除了我肯定需要知道我的总大小是否关闭,因为我需要确切地知道我的对象有多少用于 C# GC。
采用此示例函数:
void add_file(string filename, string source) {
file_source_map.insert(std::pair<const string, string>(std::move(filename), std::move(source)));
}
它分配六次(48字节),然后释放四次(32字节)。由于该对是一个右值,并且我将字符串移入其中,因此映射肯定会分配一个新节点并将右值对移入其中,而不会触发任何更多分配,当然也不必取消分配任何分配。文件名和源参数也来自右值,应该移入,而不是复制。请注意:分配器也跟踪该字符串,它不是 std::string 而是 std::basic_string<char, std::char_traits<char>, Allocator<char>>
.
仅供引用,我使用的是 MSVC。
这是我的分配器代码:
template<typename T>
class Allocator {
public :
// typedefs
typedef T value_type;
typedef value_type* pointer;
typedef const value_type* const_pointer;
typedef value_type& reference;
typedef const value_type& const_reference;
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
public :
// convert an allocator<T> to allocator<U>
template<typename U>
struct rebind {
typedef Allocator<U> other;
};
public :
Parser* parser;
inline ~Allocator() {}
inline Allocator(Allocator const& other) {
parser = other.parser;
}
inline Allocator(Parser* ptr)
: parser(ptr) {}
template<typename U>
inline Allocator(Allocator<U> const& other) {
parser = other.parser;
}
// address
inline pointer address(reference r) { return &r; }
inline const_pointer address(const_reference r) { return &r; }
// memory allocation
inline pointer allocate(size_type cnt,
typename std::allocator<void>::const_pointer = 0) {
int newsize = cnt * sizeof (T);
parser->size += newsize;
std::cout << "Allocated " << newsize << "\n";
return reinterpret_cast<pointer>(::operator new(newsize));
}
inline void deallocate(pointer p, size_type count) {
size_type size = count * sizeof(T);
::operator delete(p);
parser->size -= size;
std::cout << "Deallocated " << size << "\n";
}
// size
inline size_type max_size() const {
return std::numeric_limits<size_type>::max() / sizeof(T);
}
// construction/destruction
inline void construct(pointer p, const T& t) { new(p) T(t); }
inline void destroy(pointer p) { p->~T(); }
inline bool operator==(Allocator const& other) { return other.parser == parser; }
inline bool operator!=(Allocator const& a) { return !operator==(a); }
};
当我通过包装函数从 C# 调用 add_file(上面发布)时,我可以在控制台上清楚地看到每个分配和释放以及它们的适当大小,这是 8 的 4 次分配,我知道的 80 之一来自映射,另外两次分配 8,然后四次释放 8,这对我来说,函数中有四个冗余字符串,因为它们都是右值,没有理由发生任何释放。
最佳答案
我在 VS 2010 中运行了您的代码,我相信您看到的分配只是 Visual Studio STL 调试工具,因为所有 8 字节分配都是从 _String_val
构造函数发出的:
- 在发布版 (
_ITERATOR_DEBUG_LEVEL == 0
) 中,构造函数很简单 - 在调试 (
_ITERATOR_DEBUG_LEVEL != 0
) 中,它通过分配器分配一个_Container_proxy
(大小恰好为 8)。
如果我在 Release模式下运行您的代码,则映射的节点分配会降至 72 字节,并且 8 字节分配和释放会消失:字符串似乎已正确移动。
关于c++ - STL 中的额外分配和神奇的空间减少 - 使用右值引用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4287230/