【问题标题】:Logging allocator for std::containers?std::containers 的日志分配器?
【发布时间】:2013-02-19 11:19:24
【问题描述】:

X:我需要知道我的程序的每个部分使用了多少内存。我的程序大量使用 C++ 标准库。特别是,我想知道每个对象使用了多少内存。

我是怎么做的:记录some_vector的消费,就写

my::vector<double,MPLLIBS_STRING("some_vector")> some_vector;

在哪里

namespace my {
  template<class T, class S>
  using vector = std::vector<T,LoggingAllocator<T,S>>;
}

loggin分配器实现如下:

template<class T, class S = MPLLIBS_STRING("unknown")> struct LoggingAllocator {
  // ... boilerplate ...

  pointer allocate (size_type n, std::allocator<void>::const_pointer hint = 0) {
    log_allocation(boost::mpl::c_str<S>::value);
    // allocate_memory (I need to handle it myself)
  }
  void destroy (pointer p) ; // logs destruction
  void deallocate (pointer p, size_type num); // logs deallocation
};

问题:是否有更好的方法以通用方式获得此行为?更好的意思是,更简单,更好,不依赖于boost::mplmpllibs::metaparse,...理想情况下我只想写

my::vector<double,"some_vector"> some_vector;

并完成它。

【问题讨论】:

  • 这对我来说已经很笼统了,你想要什么更通用的?
  • 不是问题的答案,但如果只有开发人员需要知道内存使用情况,最好使用内存分析,而不是检测整个代码库。
  • @daramarak:实际上,这取决于您想要什么以及可以使用什么工具;例如,尽管我很喜欢 Massif,但你不能在生产环境中使用它,而一个简单的记录器可能是可行的。
  • @PlasmaHH 我认为它也是通用的,但整个元解析和 boost::mpl 依赖项都是需要考虑的。我希望有一种更简单的方法来做到这一点,它不依赖于 metaparse/boost::mpl。我会用这个更新问题。
  • @daramarak 用户也需要。它是一个 HPC 应用程序,我们的用户也是开发人员。但是很好的提示!谢谢!还可以考虑threadspotter、scalasca等。

标签: c++ memory-management c++11 boost-mpl allocator


【解决方案1】:

虽然可能不是“更通用”,但如果您不想自己处理所有分配,您可以从标准分配器 std::allocator 继承:

template<class T, class S = MPLLIBS_STRING("unknown"), class Allocator = std::allocator<T>>
struct LoggingAllocator : public Allocator {
    // ...
};

allocate/destroy/deallocate 函数中进行日志记录,然后调用父方法:

pointer allocate (size_type n, std::allocator<void>::const_pointer hint = 0) {
    log_allocation(boost::mpl::c_str<S>::value);
    return Allocator::allocate(n, hint);
}

但请注意,std::allocator 并不是真正为继承而设计的,例如它没有虚拟析构函数。

【讨论】:

  • 不错!这不适用于我的情况,因为我需要自己处理内存分配,但这只是给了我抽象日志记录策略的想法:D 我试图让它更简单:D
  • 如果你从另一个分配器继承,创建一个新版本的'rebind'至关重要,这样如果分配器的类型是反弹的,它返回你的分配器,而不是你继承的那个
  • 由于分配器是按值复制的,因此缺少虚拟析构函数不是问题。您可能会被切片(特别是如果基本分配器定义了 rebind 而派生的分配器没有),但正确的析构函数将运行
  • @DaveS,+1,尽管请注意在 C++11 中定义 rebind 是可选的,因此派生类只需要在基类定义的情况下执行此操作。如果基类不提供rebind,那么std::allocator_traits&lt;A&gt;::rebind_alloc 会做正确的事情。但是由于 std::allocator 确实定义了 rebind 你是绝对正确的,在这种情况下需要它
猜你喜欢
  • 2011-07-15
  • 1970-01-01
  • 1970-01-01
  • 2018-08-13
  • 2020-07-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多