-2

I've noticed that the application I am working on (written in C, BTW) is full of realloc calls, which are executed by multiple threads in parallel. What I had in mind to make it faster was to use a memory pool, so I can extend the original arrays in a very fast way. However, I don't want to create my own memory pool, I want to simply use a library that is thread-safe (or permits several threads to create pools concurrently) and supports reallocation.

I've looked at previous questions here, regarding the same question, but they failed at provide a final solution. For example:

Here the very same question was asked but only the Apache running system was suggested (Hoard is something different) but its like a using a bazooka to kill a mosquito. I need something simple.

Here the presented solution is too simple for me, because I need efficient reallocs (if possible extending the chunk contiguously in memory).

Important: Apparently many people assume the the OPer didn't make any kind of profiling and is simply coming here asking questions. I spent one week profiling my code and I know how painful reallocs are right now for my code. So please, if you know how to answer the question, thats all I need.

Community
  • 1
  • 1
a3mlord
  • 1,060
  • 6
  • 16
  • @JoachimPileborg Yes, I did test that... – a3mlord Mar 15 '15 at 15:56
  • @a3mlord, this was designed to be a funny comment, _but_ `realloc` is just OK if you're already using it – ForceBru Mar 15 '15 at 15:58
  • @ForceBru Why do you said that? I was able to estimate the time I spend on OS calls, and it is a lot. I have millions of reallocs, which are probably as heavy as mallocs. I don't get your point. – a3mlord Mar 15 '15 at 16:01
  • @a3mlord, you may want to show us your code, maybe there's no need to use `realloc`. – ForceBru Mar 15 '15 at 16:04
  • @ForceBru Essentially it is a HashTable and I don't know the number of elements that can be mapped to each bucket. If I said that every bucket has many elements, I run out of memory. – a3mlord Mar 15 '15 at 16:06
  • [These suggestions](http://stackoverflow.com/questions/7060684/memory-pools-implementation-in-c) didn't help when you googled for a [thread safe memory pool library in C](https://www.google.com/search?q=thread+safe+memory+pool+library+c)? [talloc](https://talloc.samba.org/talloc/doc/html/index.html) should fit just right for your reallocation needs. –  Mar 15 '15 at 16:23
  • @ChronoKitsune talloc doesn't have any realloc function. – a3mlord Mar 15 '15 at 17:13
  • @a3mlord You might want to [check again](https://talloc.samba.org/talloc/doc/html/group__talloc__array.html). –  Mar 15 '15 at 17:20
  • @ChronoKitsune This is not for a realloc of space that came from the pool. This is a different class of functions. – a3mlord Mar 15 '15 at 17:34
  • It is for realloc of space from a pool, but pools use a finite amount of memory. talloc lets you have the memory you requested if it exceeds the amount of available space in the pool, but it isn't allocated from the pool then, effectively calling `malloc` or whatever anyway. I think I understand what you're wanting now. I'll post an answer shortly. –  Mar 15 '15 at 19:21
  • @ChronoKitsune You are not getting my point... Lets say I allocate a struct `s` with memory from the pool. What I want is, at a later point in time, I want to extend `s` with memory from the pool as well. Of course I could just malloc the whole thing fresh from the pool and copy the previous data, but that would be a waste of memory. – a3mlord Mar 15 '15 at 19:24
  • Realloc is slower than malloc. If the space cannot be extended, it mallocs a new range, copies the data there and then frees the old data. Maybe try to malloc enough memory (by beeing wasteful) and avoid realloc? – lalala Sep 23 '20 at 19:03

1 Answers1

0

What you're looking for seems to be a resizable memory pool. Memory pools are designed for fixed amounts of memory unfortunately; that's how they minimize calls to malloc, realloc, etc.

In the end, you're probably better off looking at something like a different malloc implementation (one to consider would be Google's TCMalloc; it is a part of the gperftools project) rather than memory pools, though it is C++. If you're certain that you want pools, Boost's Pool library is worth looking into. You might be able to create a C wrapper around TCMalloc, but I'm not so certain about boost::pool.

If you want to stick to working strictly with C, and you know what you're allocating ahead of time, you could create a custom type that is resizable, which will help in optimizing your malloc and realloc calls. You could do it with simple arrays for example:

typedef struct {
    void *bytes; /* Pointer to the allocated _bytes_. */
    size_t n;    /* The number of _bytes_ used. */
    size_t max;  /* The number of _bytes_ allocated. */
} array;

The max would always be a minimum of a certain power of 2, and it would always be a power of 2 up until a certain amount of memory is used. Then it would always be a multiple of 2 to avoid hogging too much memory, and n <= max would always be true. That's a very simplistic view, but it's generally a good idea. Whenever you need to resize the array, instead of calling realloc, you check whether you need to call realloc in the first place using your own function or whether you can just increase the number of bytes used (n in this case). That's a generalized implementation that works well with standard library functions like memcpy and such and ANY data type. You might want a specialized form for, e.g., int:

typedef struct {
    int *ptr;    /* Pointer to the allocated _items_. */
    size_t n;    /* Number of _items_ used. */
    size_t max;  /* Number of _items_ allocated. */
} int_array;

The difference between this and a malloc implementation: malloc is meant to handle unknown amounts of memory with unknown type, which implies unknown size. The burden here is placed upon you to keep the type, or at least the size, of each object stored in the array consistent. Otherwise, you'll have undefined behavior.* This gets you the benefit of being able to resize the allocated memory in a reasonably optimistic manner.

I will say one thing: I'm not at all certain if that will improve your performance honestly since it duplicates the effort of a malloc implementation in most cases. TCMalloc, assuming you combined it with this idea, starts you off with ~6 MB of memory max and grows from there, perhaps by multiples of 2 or perhaps by powers of 8. I haven't checked the source quite so in-depth, so I'm not certain.

* According to ISO C, you'll technically have undefined behavior if you try to store a 4-byte int in a 4-byte float anyway, but that's why you shouldn't mix types, even if they're the same size.