【问题标题】:Boost::Mutex & MallocBoost::Mutex & Malloc
【发布时间】:2010-06-14 16:48:44
【问题描述】:

我正在尝试在 C++ 中使用更快的内存分配器。由于许可/成本,我无法使用 Hoard。我在单线程设置中使用 NEDMalloc 并获得了出色的性能,但我想知道是否应该切换到其他东西——据我所知,NEDMalloc 只是基于 C 的 malloc() 和 free() 的替代品, 不是基于 C++ 的 new & delete 运算符(我广泛使用)。

问题是我现在需要是线程安全的,所以我试图 malloc 一个被引用计数的对象(以防止过度复制),但它也包含一个互斥指针。这样,如果您要删除最后一个副本,您首先需要锁定指针,然后释放对象,最后解锁并释放互斥体。

但是,使用 malloc 创建 boost::mutex 似乎是不可能的,因为我无法将私有对象初始化为直接调用构造函数。

所以我遇到了这种奇怪的情况,我使用 new 分配锁,使用 nedmalloc 分配其他所有内容。但是当我分配大量内存时,我遇到了分配错误(当我切换到 malloc 而不是 nedmalloc 时会消失〜但性能很糟糕)。我的猜测是,这是由于内存碎片以及 nedmalloc 和 new 无法并排放置 nice 造成的。

必须有更好的解决方案。你有什么建议?

【问题讨论】:

  • 可以使用placement new直接调用构造函数。

标签: c++ thread-safety mutex allocation nedmalloc


【解决方案1】:

Google 的malloc replacement 非常快,默认情况下是线程安全的,并且易于使用。只需将其链接到您的应用程序中,它将替换行为或malloc/freenew/delete。这使得重新分析您的应用程序以验证新的分配器实际上加速了事情变得特别容易。

【讨论】:

    【解决方案2】:

    您可以重载全局运算符 newdelete 来调用您正在使用的 mallocfree 的新版本。这应该会让事情变得更好,但如果这还没有发生,我会感到惊讶。

    至于创建互斥体,使用placement new——这是手动调用构造函数的方式。 char 的静态数组将通过缓冲区完成。例如,全局变量:

    static char buf[sizeof(Mutex)];
    static Mutex *m=0;
    

    然后初始化m指针:

    m=new(buf) Mutex;
    

    (如果需要,您还可以对齐指针等,并重命名变量等。)

    可能值得注意的一点是,如果Mutex 构造函数自己分配更多内存,那么这可能是个问题。这不太可能,但可能。 (对于这种可能很少见的情况,跨平台互斥体包装器的临时实现通常没有问题,它不进行任何分配 - 或者,尽管最终会变得一团糟,只需使用#ifdef 并直接使用平台类型。在任何一种情况下,代码都不多,任何对相关系统有经验的人都可以在很短的时间内创建相关代码,没有错误。)

    正确清理以这种方式创建的对象可能很困难,所以我建议不要打扰(不,认真)。当您使用它来实现内存管理器时,让这些东西泄漏是完全可以的;没有必要为此生气。 (如果您正在使用具有进程退出概念的系统,那么操作系统几乎可以保证为您清理底层互斥体。)

    【讨论】:

    • 但这有一个副作用(它可能是一个想要的副作用),您必须为每个要使用自定义分配器管理的类提供一个新的重载。
    • 没有自定义分配器; Placement new 是标准的,全局操作符 new 和 delete 被覆盖(如果有必要的话)。我确实想到了一个问题,并将相应地编辑答案。
    • 我无法标记两个解决方案。我将在 tcmalloc 之后尝试这个。谢谢!
    【解决方案3】:

    您是否分析并验证了实际内存分配是一个足够重要的问题,替换分配器会带来有用的收益?

    NEDMalloc 线程安全吗?

    通常,默认的 c++ new/delete 操作符会在调用构造函数/析构函数之前/之后在后台使用 malloc 和 free 来进行实际的内存分配。如果它们不在您的特定情况下,您可以覆盖全局 new 和 delete 运算符来调用您希望的任何分配实现。这需要注意确保始终使用相同的分配器分配/释放内存(尤其是在处理库时)。

    【讨论】:

    • 我想知道这是否是真正导致问题的原因——混合 malloc 和 nedmalloc。我将首先尝试 tcmalloc,因为它透明地处理 new/delete,但随后我将返回并使用上面的缓冲溶液放置 new 和混乱。
    【解决方案4】:

    好吧,通常 C++ newdelete 运算符在内部调用普通 C 库函数 mallocfree(加上一些额外的魔法,比如调用 ctors 和 dtors),因此为这些函数提供自定义实现可能是足够了(这在嵌入式 C++ 开发中并不罕见,但需要一些链接器级别的工作)。你的目标是什么系统和编译器?

    【讨论】:

    • 我的目标是:gcc 4.3 - Ubuntu 10.04 gcc 4.5 - Redhat 5.5 MS VS 2005、2008 和 2010 用于 XP SP2 和 3 以及最终的 Windows 7。因此我想使用 boost + 我想使用的东西可以使用(如 nedmalloc)尽可能便携。
    • 只需要跟进——喜欢 tcmalloc,它直到最近才与 gcc 4.5 一起工作,但两者都刚刚打了补丁,现在一切正常。我唯一没有工作的构建是 VS 2010 中 64 位本机 Win 7 上的 32 位构建——但这可能不是 tcmalloc 的错。 更新: 别介意 CUDA 3.2 Beta 在我没有怀疑的方面表现不佳。 Tcmalloc 不应该受到责备。
    猜你喜欢
    • 2011-01-17
    • 1970-01-01
    • 2011-12-15
    • 1970-01-01
    • 2011-12-10
    • 2011-02-22
    • 1970-01-01
    • 2014-12-21
    • 1970-01-01
    相关资源
    最近更新 更多