簡體   English   中英

從C中的緩沖區分配

[英]Allocate from buffer in 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>是從任意指針分配內存塊和釋放內存塊的函數(可能帶有其他元數據,例如緩沖區長度等)。 是否存在此類功能和/或有更好的方法來做到這一點? 謝謝!

是的,您必須自己編寫。 它是如此簡單,真的很傻,但是與一直使用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()而是添加返回的值一個到未分配粒子的鏈接列表。 然后,下一個對ParticleAlloc()的調用者將從免費的Particles列表中刪除一個,而不是使用malloc()。 任何時候只要空閑列表上沒有更多的東西,您的ParticleAlloc()函數就可以依賴於malloc()了。 或混合使用兩種策略,這實際上是兩全其美的:如果您知道您的用戶幾乎肯定會使用至少1000個粒子,但偶爾可能需要更多,則可以從1000和如果用完了,請重新調用malloc()。 如果這樣做,則不需要malloc()的操作; 只需將它們返回到ParticleFree()時,將它們添加到未分配的粒子列表中即可。 當程序退出時,您無需費心在它們上調用free(); 操作系統將釋放進程的整個內存空間,因此所有泄漏的內存都將在此時清除。

我應該提到,由於您的問題被標記為“ C”而不是“ C ++”,因此我以C解決方案的形式回答了該問題。 在C ++中,實現同一操作的最佳方法是將“ operator new”和“ operator delete”方法添加到您的Particle類。 它們將包含與我上面顯示的代碼基本相同的代碼,但是它們會覆蓋(而不是重載)全局“ new”運算符,並且僅對於粒子類,定義一個專門的分配器來代替全局“ new”。 很棒的事情是,Particle對象的用戶甚至不必知道有一個特殊的分配器; 他們只是像往常一樣簡單地使用“ new”和“ delete”,並且很高興地沒有意識到他們的粒子對象來自一個特殊的預分配池。

哦對不起。 我只看到這個問題是C。 不是C ++。 好吧,如果是C ++,以下內容將為您提供幫助。

看一下Boost的池分配庫

在我看來,您的每個分配的大小都一樣嗎? 粒子的大小,對嗎? 如果是這樣,Boost的池分配功能將非常有效,您不必自己編寫。

您將必須編寫自己的文件,或者找到已經寫過它們並重用他們所寫內容的人。 沒有標准的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為單位打包信息。 返回的句柄允許您為不同類型(甚至多次針對同一類型)分配單獨的緩沖區。 銷毀功能會強制釋放與手柄關聯的所有空間。

分配功能為您提供了一個新的使用空間單位。 免費功能釋放了該功能以供重用。

在幕后,該代碼跟蹤正在使用的單元(可能是位圖),並可能根據需要分配額外的空間,或者在初始分配用盡時可能拒絕空間。 您可以安排它在空間用盡時或多或少地急劇失敗(因此分配器從不返回空指針)。 顯然,free函數可以驗證給定的指針是當前正在使用的緩沖區分配器句柄提供的指針。 這樣,它就可以檢測到常規free()通常無法檢測到的一些錯誤(盡管malloc()的GNU C庫版本確實進行了一些健全性檢查,而其他人不一定這樣做)。

也許嘗試這樣的事情...

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

我正在構建一個簡單的粒子系統,並希望使用結構的單個數組緩沖區來管理我的粒子。

我想你回答了:

static Particle myParticleArray[numParticles];

在程序開始時獲取分配,在程序結束時獲取釋放,很簡單。 或像您的偽代碼一樣,一次全部分配數組。 您可能會問自己為什么分配一個粒子,為什么不分配整個系統呢? 編寫API函數以獲取指向粒子數組和索引的指針。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM