从C中的缓冲区分配

时间:2012-06-24 21:01:37

标签: c memory-management particles particle-system

我正在构建一个简单的粒子系统,并希望使用结构的单个数组缓冲区来管理我的粒子。也就是说,我找不到允许我从任意缓冲区中取出malloc()和free()的C函数。这是一些显示我的意图的伪代码:

Particle* particles = (Particle*) malloc( sizeof(Particle) * numParticles );
Particle* firstParticle = <buffer_alloc>( particles );
initialize_particle( firstParticle );
// ... Some more stuff
if (firstParticle->life < 0)
    <buffer_free>( firstParticle );

// @ program's end
free(particles);

其中<buffer_alloc><buffer_free>是从任意指针分配和释放内存块的函数(可能具有缓冲区长度等附加元数据)。这些功能是否存在和/或有更好的方法吗?谢谢!

5 个答案:

答案 0 :(得分:5)

是的,你必须自己写。这很简单,真的很傻,但与单独使用malloc()和free()相比,它的性能会尖叫....

static const int maxParticles = 1000;

static Particle particleBuf[maxParticles]; // global static array

static Particle* headParticle;

void initParticleAllocator()
{
    Particle* p = particleBuf;
    Particle* pEnd = &particleBuf[maxParticles-1];
    // create a linked list of unallocated Particles
    while (p!=pEnd)
    {
        *((Particle**)p) = p+1;
        ++p;
    }
    *((Particle**)p) = NULL; // terminate the end of the list
    headParticle = particleBuf; // point 'head' at the 1st unalloc'ed one
}

Particle* ParticleAlloc()
{
    // grab the next unalloc'ed Particle from the list
    Particle* ret = headParticle;
    if (ret)
        headParticle = *(Particle**)ret;
    return ret; // will return NULL if no more available
}

void ParticleFree(Particle* p)
{
    // return p to the list of unalloc'ed Particles
    *((Particle**)p) = headParticle;
    headParticle = p;
}

你可以修改上面的方法,根本不用任何全局静态数组开始,并在用户调用ParticleAlloc()时首先使用malloc(),但是当返回Particles时,不要调用free()而是将返回的值添加到unalloc'ed粒子的链接列表中。那么ParticleAlloc()的下一个调用者将从免费粒子列表中获取一个,而不是使用malloc()。只要空闲列表中没有更多内容,您的ParticleAlloc()函数就可以回退到malloc()。或者使用两种策略的混合,这两种策略实际上是最好的:如果您知道您的用户几乎肯定会使用至少1000个粒子,但偶尔可能需要更多,您可以从1000的静态数组开始如果你用完了,就回到调用malloc()。如果你这样做,malloc()'ed的那些不需要特殊处理;当它们返回到ParticleFree()时,只需将它们添加到unalloc'ed粒子列表中。当你的程序退出时,你不需要在它们上面调用free();操作系统将释放进程的整个内存空间,因此任何泄漏的内存都会在此时清除。

我应该提一下,因为你的问题被标记为“C”而不是“C ++”,我以C解决方案的形式回答了它。在C ++中,实现同样的事情的最好方法是在Particle类中添加“operator new”和“operator delete”方法。它们将包含与我上面显示的代码基本相同的代码,但是它们覆盖(不重载)全局“new”运算符,并且仅对于Particle类,定义一个替换全局“new”的专用分配器。很酷的是,Particle对象的用户甚至不必知道有一个特殊的分配器;他们只是像往常一样使用“新”和“删除”,并且仍然没有意识到他们的粒子对象来自一个特殊的预分配池。

答案 1 :(得分:1)

哦,抱歉。我只看到这个问题。不是C ++。好吧,如果它是C ++,以下内容可以帮助你。

看看Boost's pool allocation library

听起来我的每个分配都是相同的大小?粒子的大小,对吗?如果是这样,来自Boost的池分配功能将非常有效,您不必自己编写。

答案 2 :(得分:0)

你必须自己编写,或者找一个已经编写过它们并重用它们所写内容的人。没有标准的C库来管理该场景,AFAIK。

您的“缓冲区分配”代码可能需要4个函数:

typedef struct ba_handle ba_handle;

ba_handle *ba_create(size_t element_size, size_t initial_space);
void  ba_destroy(ba_handle *ba);

void *ba_alloc(ba_handle *ba);
void  ba_free(ba_handle *ba, void *space);

create函数将进行空间的初始分配,并安排以element_size为单位分组信息。返回的句柄允许您为不同类型(或甚至多次使用相同类型)分别进行缓冲区分配。 destroy函数强制释放与句柄相关的所有空间。

allocate函数为您提供了一个新的空间单元供您使用。 free函数释放它以供重用。

在幕后,代码会跟踪正在使用的单元(可能是位图),并可能根据需要分配额外的空间,或者在初始分配用完时可能会拒绝空间。当空间不足时,您可以安排它或多或少地显着失败(因此分配器永远不会返回空指针)。显然,自由函数可以验证它所给出的指针是由当前正在使用的缓冲区分配器句柄提供的指针。这允许它检测常规free()通常不会检测到的一些错误(尽管malloc()等的GNU C库版本确实似乎做了一些其他人不一定做的健全性检查。)

答案 3 :(得分:0)

也许尝试这样的事情......

Particle * particles[numParticles];
particles[0] = malloc(sizeof(Particle));
initialize_particle( particle[0] );

// ... Some more stuff
if (particle[0]->life < 0)
    free( particle[0] );

// @ program's end
// don't free(particles);

答案 4 :(得分:-1)

我正在构建一个简单的粒子系统,并希望使用结构的单个数组缓冲区来管理我的粒子。

我想你回答了这个问题:

static Particle myParticleArray[numParticles];

获取在程序开始时分配并在最后解除分配,简单。或者像你的伪代码和malloc一样。您可能会问自己为什么要分配单个粒子,为什么不分配整个系统?编写API函数以获取指向粒子数组和索引的指针。