Я заменил стандартный распределитель на распределитель, который будет "звонить домой" о том, сколько памяти он потребляет. Сейчас я перебираю часть своего кода и задаюсь вопросом, какого черта он выделяет, а затем освобождает так много записей.
Просто для справки, я не пытаюсь предварительно оптимизировать свой код или что-то еще, я в основном любопытен, за исключением того, что мне определенно нужно знать, выключен ли мой общий размер, потому что мне нужно точно знать, сколько мой объект использует для 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 байт). Так как пара является rvalue, и я переместил строки в нее, карта наверняка выделит новый узел и переместит в него пару rvalue, не вызывая больше никаких выделений и, конечно же, не требуя отмены выделения. Аргументы имени файла и источника также взяты из значений rvalues и должны быть перемещены, а не скопированы. Просто примечание: строка также отслеживается распределителем, это не 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); }
};
Когда я вызываю add_file (опубликованный выше) из C # через функции-оболочки, я ясно вижу каждое выделение и освобождение и их соответствующие размеры на консоли, и это четыре выделения из 8, одно из 80, которое, как я знаю, происходит из карта, еще два распределения по 8, а затем четыре освобождения по 8, что говорит мне, что в функции есть четыре избыточные строки, потому что все они являются значениями и нет причин для каких-либо освобождений.