2012-06-24 24 views
2

我建立一个简单的粒子系统,并希望使用结构的单一阵列缓存来管理我的微粒分配。也就是说,我找不到一个C函数,它允许我从任意缓冲区中获取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>是分配的功能和从任意的指针自由存储器块(可能具有附加的元数据,例如缓冲区长度,等)。这样的功能是否存在和/或有没有更好的方法来做到这一点?谢谢!

+0

你可以为(struct?)粒子添加定义吗?它是否包含指针? – wildplasser

+1

+1。据我所知,C没有做你想做的事。 C++使用* placement new *语法来实现它,这很有趣。然而,没有什么能够阻止你分配一个粒子数组(无论是堆栈还是堆),然后根据需要每次分配一个粒子的存储。 – thb

+0

@thb:我不认为这是一个放置新场景。 OP需要自动内存管理,但要隔离到已定义的内存区域。 –

回答

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; 
} 

您可以修改方法上面不与任何全球启动静态数组在所有,使用malloc()在第一次当用户调用ParticleAlloc(),但在返回时的颗粒,不调用free(),而是添加返回那些以unalloc'ed颗粒的链接列表。然后,下一个给ParticleAlloc()的调用者将从一个免费粒子列表中获得一个,而不是使用malloc()。任何时候没有更多的空闲列表中,你的ParticleAlloc()函数可能会回落到malloc()。或者使用两种策略的组合,这两种策略确实是两全其美的:如果你知道你的用户几乎肯定会使用至少1000个粒子,但偶尔可能需要更多,你可以从一个1000的静态数组开始,如果你用完了,请回到调用malloc()的位置。如果你这样做,malloc()的编辑就不需要特殊的处理。只需将它们添加到未分配的粒子列表中,当它们返回到ParticleFree()时。当你的程序退出时,你不需要打扰自己调用free();操作系统将释放进程的整个内存空间,因此任何泄漏的内存都将在此时清除。

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

+0

你的代码可以工作,但是你能否解释你的链表是如何存储的?如何翻译? '*((Particle **)p)= p + 1;' – Ulterior

+0

@Ulterior - Cool ...我没有真正测试它,所以我很高兴它可以工作。你和Grimless一样吗?他们关键的策略是,当粒子对象没有被使用(即它们在未分配的链表上)时,它们作为列表的内在“下一个”指针。为此,我将它们转换为粒子指针(粒子*)。要将粒子对象的地址写入一个,我将指针p作为指向粒子*或粒子**的指针,然后对其进行解引用,为其分配一个粒子*。在这种特殊情况下,我将下一个Particle的地址写入它,形成链表。 – phonetagger

+0

这种设计的工作原理与sizeof(粒子)> = sizeof(粒子*))一样。如果粒子比指针小,则失败。 –

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); 

的创建功能会做空间的初始分配,并安排了包裹在element_size单位的信息。返回的句柄允许你为不同类型分配不同的缓冲区分配(甚至可以多次使用相同的类型)。破坏功能强制释放与句柄相关的所有空间。

的分配功能,为您提供了使用空间的新单元。免费函数释放重用。

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

+0

同意。值得注意的是,你正在向C++等同于new []和delete []。 – djechlin

+0

已编辑答案要好得多,我担心会遇到这种情况,我将不得不采取我的堆分配技术来正确实施这个方法,很可能会使OSS帮助解决这个问题,谢谢! – Grimless

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); 
+0

这就是确切的情况我试图避免:mallocing每个粒子的基础上malloc可以变得非常缓慢,当内存开始用完,我失去了24个字节的每个malloc,浪费了24K的1,000粒子系统通常,我试图有效调整缓冲区的大小以重新使用粒子而不再击中malloc – Grimless

+0

这也是不正确的:particle [0]不是指针。 – wildplasser

+0

将粒子更改为粒子*数组,但我想它是一个毫无意义的问题。 – gpian

1

哦,对不起。只有我看到这个问题。不是C++。那么,如果它是C++,以下内容将帮助你。

看看Boost's pool allocation library

听起来我的每个分配都是相同的大小?一个粒子的大小,是否正确?如果是这样的话,Boost的池分配功能将会非常有效,而且你不必自己编写。

-1

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

我想你的答案是:

static Particle myParticleArray[numParticles]; 

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

+1

这并不能解决我的问题。我需要能够找到粒子阵列中最好的可用位置,以产生下一个发射粒子。此外,如果我关闭粒子或希望在屏幕上显示更多粒子,则该阵列不能调整大小或释放。这与我的目标明显相反,在考虑之前并没有花时间和精力来解决这个问题。 – Grimless

+0

嗨Grimless,因为你说'C''简单'和'单个数组',我只是想提出一个替代方案,不需要额外的库或花式的malloc/free。听起来像(从其他评论和AFAIK),你必须编写你自己的malloc/free或者在标准之外找到一个lib。根据你的描述(大量的粒子),它听起来像你可能想要操纵粒子集合,而不是单个粒子。我认为你正在编写粒子接口,所以你可以这样写: ParticleInit(粒子*粒子,无符号索引); –

+0

没有意图听起来没有思想。 –