首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >线程安全内存池

线程安全内存池
EN

Stack Overflow用户
提问于 2011-04-20 22:22:19
回答 3查看 12.2K关注 0票数 13

我的应用程序目前性能非常关键,每帧请求350万个对象。最初,为了使球滚动,我new'd所有的东西,并使应用程序工作和测试我的算法。应用程序是多线程的.

一旦我对性能感到满意,我就开始为我的对象创建一个内存管理器。显而易见的原因是内存碎片和浪费。由于内存碎片,应用程序在崩溃之前不能继续超过几个帧。我已经检查了内存泄漏,并且知道应用程序是无泄漏的。

因此,我开始使用TBB的concurrent_queue创建一个简单的内存管理器。队列存储应用程序允许使用的最大元素集。需要新元素的类会从队列中弹出元素。根据英特尔的文档,try_pop方法是无锁的.就内存消耗而言,这是非常有效的(虽然仍然存在内存碎片,但没有以前那么多)。我现在面临的问题是,根据我自己的简单分析器,应用程序的性能下降了大约4次(我无法访问商业分析器,也不知道任何将在实时应用程序上工作的).请提出任何建议)。

我的问题是,是否有一个线程安全的内存池是可伸缩的。池的一个must-have特性是元素的快速循环并使其可用。如果没有,在性能方面有什么提示/技巧吗?

编辑:,我想我会更多地解释这个问题。我可以很容易地初始化n个数组,其中n是线程数,然后开始使用每个线程数组中的对象。这将完美地适用于某些情况。在我的例子中,我也在回收元素(可能是每一个帧),它们可以在数组的任意点被回收;也就是说,它可能来自数组的elementArray[0]elementArray[10]elementArray[1000]部分。现在,我将有一个由准备使用的元素和正在使用的元素组成的碎片数组:(

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2011-04-21 00:21:24

正如注释中所说的,不要获得线程安全内存分配器,每个线程分配内存.

正如您在更新中所暗示的,您需要有效地管理免费/在使用中。这是一个非常直截了当的问题,考虑到一个常量类型,并且没有并发性。

例如(从我的头顶,未经测试):

代码语言:javascript
复制
template<typename T>
class ThreadStorage
{
    std::vector<T> m_objs;
    std::vector<size_t> m_avail;

public:
    explicit ThreadStorage(size_t count) : m_objs(count, T()) {
        m_avail.reserve(count);
        for (size_t i = 0; i < count; ++i) m_avail.push_back(i);
    }

    T* alloc() {
        T* retval = &m_objs[0] + m_avail.back();
        m_avail.pop_back();
        return retval;
    }

    void free(T* p) {
        *p = T(); // Assuming this is enough destruction.
        m_avail.push_back(p - &m_objs[0]);
    }
};

然后,对于每个线程,有一个ThreadStorage实例,并根据需要调用alloc()和free()。

您可以添加智能指针来管理对free()的调用,如果代价高昂,还可以优化构造函数/析构函数调用。

您还可以查看boost::pool。

更新:

新的要求,保持跟踪的东西已经被使用,以便他们可以在第二次处理,在我看来有点不清楚。我认为您的意思是,当主处理在对象上完成时,您不需要释放它,而是在第二阶段处理中保留对它的引用。有些对象将被释放回池,而不用于第二阶段的处理。

我想你想要在同一个线程中完成这个任务。

首先,您可以将这样的方法添加到ThreadStorage中,当您想要对所有未发布的T.实例进行处理时调用它,不需要额外的簿记。

代码语言:javascript
复制
void do_processing(boost::function<void (T* p)> const& f) {
    std::sort(m_avail.begin(), m_avail.end());

    size_t o = 0;
    for (size_t i = 0; i != m_avail.size(); ++i) {
        if (o < m_avail[i]) {
            do {
                f(&m_objs[o]);
            } while (++o < m_avail[i]);
            ++o;
        } else of (o == m_avail[i])
            ++o;
    }

    for (; o < m_objs.size(); ++o) f(&m_objs[o]);
}

假设没有其他线程使用ThreadStorage实例,这是合理的,因为它是设计为线程本地的。再一次,从我的头顶上,未经测试。

票数 7
EN

Stack Overflow用户

发布于 2011-04-21 09:34:53

谷歌的TCMalloc

TCMalloc为每个线程分配一个线程本地缓存。从线程本地缓存中满足小的分配。对象根据需要从中央数据结构移动到线程本地缓存,并使用定期垃圾收集将内存从线程本地缓存迁移回中央数据结构。

性能:

TCMalloc比glibc2.3malloc.ptmalloc2大约需要300纳秒才能在2.8 GHz P4 (对于小型对象)上执行malloc/free对。对于同一个操作对,TCMalloc实现大约需要50纳秒.

票数 4
EN

Stack Overflow用户

发布于 2011-04-21 07:23:17

您可能想看看jemalloc

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/5737344

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档