4 ms·
And if you are not using arena -- realloc() is your best bet. And no, it won't move your memory around into larger areas every time you call it. Most of the tim
by habibur 3y ago
And if you are not using arena -- realloc() is your best bet. And no, it won't move your memory around into larger areas every time you call it. Most of the time it will simply bump up the allocation end point. This happens more frequently than you think.
In my code I don't use allocated_length and used_length seperately in dynamic vectors. Simply realloc() every time one element is added. No measurable difference in speed, and code is much more clean.
- PhilipRoman 3y agoWould be interesting to check how often realloc actually reuses pointers (and for what allocation sizes this happens) in real world applications.
- nwellnhof 3y ago> No measurable difference in speed, and code is much more clean. This only works with some malloc implementations. There are platforms where this will result in quadratic behavior, so don't do this if you want to write portable code.
- jandrese 3y agoYeah, I was just thinking that line of thought was notorious in the past for some serious performance issues. It's one reason you sometimes see arena allocators doubling the memory every time they have to grow. Might be something to benchmark on your system before using. It's also possible those badly behaving allocators are in the past and this is fine to do now.
- kevin_thibedeau 3y agoThey're not in the past. There are systems that don't even implement realloc().
- Someone 3y ago> realloc() is your best bet. And no, it won't move your memory around into larger areas every time you call it. That’s true. > Most of the time it will simply bump up the allocation end point That depends on your allocator and usage patterns. I would think that, in real world usage, it will reallocate fairly frequently, but don’t have and can’t find data on that. Reason is that I would expect the allocator to, normally, allocate blocks tight together and most reallocations to grow the size by more than the granularity of the memory allocator (which typically is in the order of 16 bytes) The latter often applies too if you “don't use allocated_length and used_length seperately in dynamic vectors. Simply realloc() every time one element is added” Or am I wrong? How large is your initial alloc? Edit: slab allocators may show such good behavior.
- habibur 3y ago> Or am I wrong? How large is your initial alloc? Zero. Most of the time. When I don't know the exact requirement before hand. > Reason is that I would expect the allocator to, normally, allocate blocks tight together and most reallocations to grow the size by more than the granularity of the memory allocator Now look at it like this. Even if I wrote my own allocator with malloc(), free() and realloc(), I would have written it such a way that the first time I found a pointer getting realloc()-ed I would have added an extra 60% at its end assuming this pointer has a trend to grow. And for subsequent small increment calls use space at the end. I don't see why C library's allocator writers wouldn't have thought the same. Even if on some platform it's not done for some reason, that can be replaced with your own implementation. Add with it the fact that OS is also optimizing your memory usage, your allocs are virtual pages mapped to actual physical ram. And who knows how deep these caches go at processor level. You are basically caching over caching and so on. This is similar to "reading a file in memory" because "accessing from disk is so slow". That's so much 90s thought. Your file will be cached in memory by the OS whenever you access it the first time and you have sufficient free RAM available for cache. But one doesn't need to assume the above to be true. Simply measure and check for yourself. If your findings don't match your understandings, there are alternate explanations.
- jstimpfle 3y ago
- lelanthran 3y ago> And if you are not using arena -- realloc() is your best bet. And no, it won't move your memory around into larger areas every time you call it. Most of the time it will simply bump up the allocation end point. This happens more frequently than you think. And, as far as I can tell on the most common implementations, `realloc` just does a pointer adjustment when you shrink[1] the array, so the next `realloc` to expand the array again simply does the pointer bump thing. Over time[2], you effectively get a arena allocator from that single realloc()ed block just by expanding and shrinking the array. [1] Just don't call `realloc (0, ...)` [2] For my next project I'm going to make an arena-allocator interface that is just a thin wrapper around realloc.
- gkfasdfasdf 3y agoOne of the benefits of the arena that the OP mentions though is that old pointers are still valid as long as the arena is still valid. That's not necessarily the case with realloc. Interesting idea to skip explicitly tracking capacity with realloc though. That does seem convenient, and if the allocator is fast, sure, why not?
- abainbridge 3y ago> no, it won't move your memory around into larger areas every time you call it. Most of the time it will simply bump up the allocation end point. This happens more frequently than you think. I just tried some simple "I want to grow my block of memory" test cases. A malloc of 1000 bytes couldn't be increased by a single byte without being moved to a new location. An allocation of 1 million bytes couldn't be increased by 1% without being moved to a new location. https://godbolt.org/z/Gr4bchxv5 https://godbolt.org/z/Gr4bchxv5
- habibur 3y ago#include <stdio.h> #include <stdlib.h> int main(){ int same=0; int moved=0; char* temp=malloc(16); for(int i=0; i<10000; i++){ char* temp2=realloc(temp,(i+2)*16); if(temp!=temp2){ moved++; temp=temp2; } else same++; } printf("ptr moved %d, reused %d times\n",moved,same); } Tried the above. Ptr moved 7 times and is reused 9993 times. But, what you want to test is what you identify as your need. No point in explaining more.