我正在阅读并试验本书的指示,
http://shop.oreilly.com/product/0636920028000.do
在本书的第6章避免malloc / free Overhead 标题下 作者建议如何在进行大量结构内存分配/解除分配时避免malloc / free开销。
以下是他编写函数的方式,
#define LIST_SIZE 10
Person *list[LIST_SIZE];
void initializeList()
{
int i=0;
for(i=0; i<LIST_SIZE; i++)
{
list[i] = NULL;
}
}
Person *getPerson()
{
int i=0;
for(i=0; i<LIST_SIZE; i++)
{
if(list[i] != NULL)
{
Person *ptr = list[i];
list[i] = NULL;
return ptr;
}
}
Person *person = (Person*)malloc(sizeof(Person));
return person;
}
void deallocatePerson(Person *person)
{
free(person->firstName);
free(person->lastName);
free(person->title);
}
Person *returnPerson(Person *person)
{
int i=0;
for(i=0; i<LIST_SIZE; i++)
{
if(list[i] == NULL)
{
list[i] = person;
return person;
}
}
deallocatePerson(person);
free(person);
return NULL;
}
我从他的代码中了解到,他创建了一个内存池数组,指向 struct person 类型,然后用NULL初始化每个数组元素。
接下来,我们将使用 getPerson 函数从池中获取内存。这个函数检查!= NULL ,我认为每次都会失败。所以它也是一样的,因为malloc和内存不会随时从池中分配。
答案 0 :(得分:6)
接下来,我们将使用getPerson函数从池中获取内存。这个函数检查我认为每次都会失败的
getPerson
。
只要您反复继续致电getPerson
,检查就会失败。但是,如果混合使用returnPerson
和NULL
,则某些returnPerson
检查会成功,因为NULL
会将非struct Person
值放入数组中。< / p>
此观察结果是理解该方法的关键:数组用作malloc
块的小型临时存储,这些块已分配malloc
,但不再使用。如果有可用的代码,您的代码将从此特殊列表中获取可用的块,而不是再次调用LIST_SIZE
。
在您进行数千次分配但在任何给定时间内永远不会保留超过malloc
个对象的情况下,LIST_SIZE
来电的数量仅限于Person *list[LIST_SIZE]
。
这是处理开销的方法吗?
这是使用旁视列表的一种变体,这是一种非常重要的优化技术,微软创建了an API for its use in driver code。一种更简单的方法是使用next
作为已发布块的堆栈,即使用最后发布的块的索引而不使用循环。
另一种方法是设置这些块的链表,重用块本身的内存来存储{{1}}指针。但是,对于介绍性的嘘声,这种技术可能过于复杂。
答案 1 :(得分:2)
首先,你的作者在这里指的是开销吗?对于动态内存分配,我们调用malloc
来分配内存,free
来释放内存。此外,在此过程中,操作系统需要从堆中搜索可用内存并分配相同的内存。为了避免这种开销,他只是建议在应用程序加载的最开始,如果你知道可能的动态内存分配到struct
的频率,你可以预先保留一个内存池,这将减少分配并且显着地释放内存开销。这在某种程度上是正确的,如果您的服务器已经运行了大量应用程序并且处理器非常繁忙,那么您可以采用这种方法。但也有缺点。在这种情况下,您已经预先从堆中保留了一个内存池。如果使用不当,将导致内存管理不善。
答案 2 :(得分:0)
我认为示例的重点可能是Person
对象保存了指向附加内存的指针。我们可以从deallocatePerson
函数看到结构中有三个指向字符串的指针:
void deallocatePerson(Person *person)
{
free(person->firstName);
free(person->lastName);
free(person->title);
}
这意味着要构造一个完整的Person
,您需要多次调用malloc
(1表示结构本身,3表示字符串)。
因此,通过保存完整的结构,包括其字符串,一个getPerson
调用会将四个调用替换为malloc
。这样可以节省一些执行时间。
否则,如果malloc
/ free
内部拥有一个类似的数组或最近使用的内存块的链表,我不会感到惊讶。如果您只有free
一个大小正确的内存块,则对malloc
的新调用可能会很快找到非常的块。
如果Person
是一个简单的结构而没有指向其他存储的指针,那么本地缓存不会 可能会提高性能(但可能会改为添加开销做线性搜索)。