简体   繁体   English

C:哪个更好? malloc结构指针数组或结构数组?

[英]C: Which is better? Malloc array of pointers to structures, or array of structures?

I've been curious about this for a while now, when using structures inside of arrays, as far as memory allocation is concerned, is it better to allocate a new structure for each entry in the array, or is it better to allocate enough space in the array for N structures. 我一直对此感到好奇,当使用数组内部的结构时,就内存分配而言,为数组中的每个条目分配新结构是否更好,或者更好地分配足够的空间在N个结构的数组中。

//pointer based:
struct myStructure ** tmp = malloc(sizeof(struct myStructure *) * N);
tmp[0] = malloc(sizeof(struct myStructure));
tmp[0]->whatever = true;

//or structure in the array:
struct myStructure * tmp = malloc(sizeof(struct myStructure) * N);
tmp[0].whatever = true

Are there any benefits over one or the other? 是否有任何好处超过一个或另一个? I feel like using the second form is better practice because you end up with fewer small malloc calls, but there might be cases where you can only use the first method. 我觉得使用第二种形式是更好的练习,因为你最终会减少较小的malloc调用,但可能会出现只能使用第一种方法的情况。

Any insight into this? 对此有何见解?

Thanks! 谢谢!

In general I'd use the second way, since, if you use all the slots, it: 一般来说,我会使用第二种方式,因为,如果你使用所有的插槽,它:

  • it uses slightly less memory (N times the size of a pointer); 它使用的内存略少(指针大小的N倍);
  • fragments less the heap; 碎片少了堆;
  • avoids N calls to malloc / free (=>it's faster and simpler to allocate/deallocate); 避免N次调用malloc / free (=>分配/解除分配更快更简单);
  • avoids double indirection when accessing each structure (very small improvement). 在访问每个结构时避免双重间接(非常小的改进)。

On the other hand, the first way may be convenient if you are not going to use all the slots of the array (but you must be able to store many struct s on demand) and your struct is very big, so saving that memory is worth the effort. 另一方面,如果你不打算使用数组的所有插槽(但你必须能够按需存储许多struct )并且你的struct非常大,第一种方式可能很方便,所以保存内存是值得努力。 Also, it may be worth if you need to change the order of your struct s cheaply (although you could do that also with the second method by using a separated array of pointers). 此外,如果您需要廉价地更改struct的顺序(尽管您也可以使用第二种方法通过使用分离的指针数组),这可能是值得的。

Usually, the second is better [IMO] - it will probably be cheaper [both memory and time], and definetly will be easier to maintain. 通常,第二个更好 [IMO] - 它可能会更便宜[内存和时间],并且肯定会更容易维护。

However, at some cases, the second approach might fail - when the first will succeed. 但是,在某些情况下, 第二种方法可能会失败 - 当第一种方法成功时。 This might happen due to memory fragmentation - there is enough memory for all your structs, it is just not in "one place" in your memory. 这可能是由于内存碎片造成的 - 所有结构都有足够的内存,它只是不在你记忆中的“一个地方”。

There are currently three very good answers why you should use the second approach, so I won't duplicate their answers. 目前有三个非常好的答案,为什么你应该使用第二种方法,所以我不会复制他们的答案。 I do want to say that the first approach has several benefits: 我想说第一种方法有几个好处:

  • The first array is far easier to grow and shrink based on their actual need in the system. 根据系统中的实际需要,第一个阵列更容易增长缩小 Growing the first array of pointers is pretty easy -- each element is four or eight bytes long total so doubling the size of the array won't cost too much. 增加第一个指针数组非常简单 - 每个元素总长度为4或8个字节,因此将数组大小加倍不会花费太多

    The second array of actual structures might be significantly larger (by sizeof struct foo times the number of elements), and growing the array even slightly might run out of memory if realloc(3) does not have sufficient free space to work with. 第二个实际结构数组可能要大得多(通过sizeof struct foo乘以元素数),如果realloc(3)没有足够的可用空间,那么甚至可能会略微增长数组。

  • The first array gives you the ability to refer to objects in the system by "handles" and re-arrange their memory as needs dictate. 第一个数组使您能够通过“句柄”引用系统中的对象,并根据需要重新排列其内存。 You could allocate the underlying objects in page-sized slabs and re-compact objects towards nearly-full slabs -- allowing you to return pages to the operating system for other use later. 您可以在页面大小的平板中分配底层对象,并将对象重新压缩到几乎完整的平板 - 允许您将页面返回到操作系统以供以后使用。 Other objects in the system would have to go through another layer of indirection to get to referenced objects, but those client objects ("referents"?) would not need to have their pointers updated when you move objects. 系统中的其他对象必须通过另一个间接层来获取引用的对象,但是当您移动对象时,那些客户端对象(“指示对象”?)不需要更新其指针。

  • The lifetime of objects in the first array is "decoupled" -- some of those objects might live for a very long time and others might live for mere milliseconds. 第一个数组中对象的生命周期是“解耦的” - 这些对象中的一些可能存在很长时间,而其他对象可能仅存活毫秒。 In the second array, the entire array has the same lifetime. 在第二个数组中,整个数组具有相同的生命周期。 You could add an additional data structure to the second array to manage which objects are live and which are dead, or add new fields in the structures to indicate which are live and dead, but both approaches require more work. 您可以向第二个数组添加一个额外的数据结构来管理哪些对象是活动的,哪些是死的,或者在结构中添加新字段以指示哪些是活动的和死的,但这两种方法都需要更多的工作。 With the first array, if the pointer is non- NULL , then the object is live. 对于第一个数组,如果指针是非NULL ,则该对象是实时的。

Both approaches have their benefits. 这两种方法都有其优点。 Pick the right one for the job at hand. 为手头的工作挑选合适的一个。

Structure in the array is usually better; 阵列中的结构通常更好; you should use that unless you have a reason to use the other form. 你应该使用它,除非你有理由使用其他形式。

From a code correctness point of view, you should handle malloc() fails. 从代码正确性的角度来看,你应该处理malloc()失败。 If you have 1000 malloc()s in a loop, you're more likely to make a programming error in your error-handling code. 如果循环中有1000个malloc(),则更有可能在错误处理代码中出现编程错误。 Similarly, if your data structure is more complex you're more likely to leak something. 同样,如果您的数据结构更复杂,您更有可能泄漏某些东西。 So the single malloc() is easier. 所以单个malloc()更容易。

From a allocation speed point of view, malloc() obviously takes time to run, so a single malloc() will usually be faster. 从分配速度的角度来看,malloc()显然需要时间来运行,因此单个malloc()通常会更快。

From a memory size point of view, malloc() usually has some overhead on each allocation. 从内存大小的角度来看,malloc()通常在每次分配时都会有一些开销。 And obviously the pointers are an extra cost. 显然,指针是一个额外的成本。 So if you allocate 1000 16-byte structures, you might end up with 16 bytes per structure in malloc overhead and an 8-byte pointer, total 40,016 bytes. 因此,如果分配1000个16字节结构,则最终可能会在malloc开销中使用每个结构16个字节,并使用8个字节的指针,总计40,016个字节。 Doing a single allocation will only take up 8,016 bytes. 执行单个分配只需要8,016个字节。

From an access speed point of view, the single array is likely to be faster, especially if the structures are small or you read the structures in order. 从访问速度的角度来看,单个阵列可能更快,特别是如果结构很小或者您按顺序读取结构。 If the structures are small, then several of them will fit in a single cache line so they can be read/written as a group. 如果结构很小,那么它们中的一些将适合单个高速缓存行,因此它们可以作为一组读/写。 If you read the structures in order, the CPU is likely to notice the linear access to the big array and preload it into the cache. 如果按顺序读取结构,CPU可能会注意到对大数组的线性访问并将其预加载到缓存中。 If you use a pointer array and separate allocations, then the memory layout is more random and neither of these optimizations will work. 如果使用指针数组和单独的分配,则内存布局更随机,这些优化都不起作用。 Also, since you're accessing more data (the pointers), your algorithm will fall out of data cache sooner. 此外,由于您正在访问更多数据(指针),因此您的算法将更快地脱离数据缓存。

From a memory fragmentation point of view, it depends. 从内存碎片的角度来看,这取决于。 If you have large-enough structures (a significant fraction of your total RAM), then you might get into a situation where there's not enough contiguous free memory to allocate a single big array, but there is enough to allocate an array of pointers and the individual structures. 如果你有足够大的结构(占你总RAM的很大一部分),那么你可能会遇到没有足够的连续空闲内存来分配一个大数组的情况,但是有足够的分配一个指针数组和个人结构。 (Eg if you have a 32-bit program on an OS that limits you to 2GB of memory, and your memory allocator has allocated something else half way through the memory, then you can't do a single 1.5GB allocation but you could do 15 100MB allocations). (例如,如果你的操作系统上的32位程序限制你的2GB内存,你的内存分配器已经分配了一半的内存,那么你不能做一个1.5GB的分配,但你可以做15 100MB分配)。 This kind of scenario is rare, because people don't usually work with data that large. 这种情况很少见,因为人们通常不会处理大数据。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM