从C中的缓冲区分配

Gri*_*ess 2 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);
Run Code Online (Sandbox Code Playgroud)

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

pho*_*ger 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;
}
Run Code Online (Sandbox Code Playgroud)

你可以修改上面的方法,根本不用任何全局静态数组,并在用户调用ParticleAlloc()时首先使用malloc(),但是当返回Particles时,不要调用free()而是添加返回的那些未分配粒子的链表.那么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对象的用户甚至不必知道有一个特殊的分配器; 他们只是像往常一样使用"新"和"删除",并且仍然幸福地发现他们的粒子对象来自一个特殊的预分配池.