HackerTrans
TopNewTrendsCommentsPastAskShowJobs

8dcc

no profile record

Submissions

Writing a simple pool allocator in C

8dcc.github.io
307 points·by 8dcc·2 lata temu·143 comments

comments

8dcc
·2 lata temu·discuss
> I would do exactly the dual: the chunk's size should be defined at pool creation, so that you can create multiple pools, each dedicated to one specific kind of object.

This is supported in my 'libpool' project. I thought I mentioned it in the article, but now I am not so sure.

https://github.com/8dcc/libpool/blob/main/src/libpool.h#L51

> Similarly, I don't like exposing pool_expand(): too much burden on the user. Expansion should be automatically triggered by pool_alloc() whenever the current pool is exhausted.

I feel like this shouldn't be too hard to do, but I actually did write a function for this in another project I am working on.

https://github.com/8dcc/sl/blob/9ddd84d75ffc3b0ba1373bc13bc6...

> This would also allow a much simpler pool_new() that just initializes its pointers to NULL, leaving it to the first invocation of pool_alloc() to actually do the first allocation.

I didn't think of this, but I rather keep the two functions separate, specially for readability in the article.
8dcc
·2 lata temu·discuss
I am not sure what you mean, exactly. There are some other valgrind macros that need to be called for pointers other than the ones returned by 'malloc'. More importantly, the memory regions need to be marked as 'NOACCESS' after we are done using them from the pool allocator, or valgrind will complain; that's why I set them back to 'DEFINED' before writing to them in other functions.

This is my first time using valgrind, however, so I might just be confused about what you mean, and there is a simpler way of doing all this.
8dcc
·2 lata temu·discuss
You are right, sorry about that. I fixed it on the most recent commit (73526e0).
8dcc
·2 lata temu·discuss
> I thought the whole point of writing a custom allocator was to not use the system allocator beyond statically allocating a huge block of memory upfront and then managing that yourself, is it not?

Yes, that's what the article is basically about. The other problems you mention only happen when trying to expand an existing pool, which might not be necessary for some people.
8dcc
·2 lata temu·discuss
(In case you missed my other post, I ended up adding valgrind support in the article and in the 'libpool' project.)

> I integrated the TXR Lisp garbage collector with valgrind.

That's funny, because when I said "for other projects I am working on", I specifically meant a Lisp interpreter which uses a memory pool and garbage collection (I am still working on implementing this last part, anyway). I am very happy about the fact that I can continue using valgrind in this project.
8dcc
·2 lata temu·discuss
Actually, I have one question. You said:

> The actual benchmark program itself can be as simple as allocating and deallocating in a loop [...]

What do you mean, exactly? Deallocating immediately after allocating? I feel like there would be a big difference between that and allocating multiple blocks before freeing them.
8dcc
·2 lata temu·discuss
Wow. This is probably the best comment I have ever seen on HN. Thank you so much for the information, I will add benchmarking to my 'libpool' project and mention it in the article. I can't think of any questions right now, but I will let you know if anything comes up. Thank you again. :)
8dcc
·2 lata temu·discuss
Yes, you are right. Do you have any suggestions on how I should do the benchmarking? I am not sure how this is usually done, but if the output is some kind of graph, I would also like to know how these graphs are usually produced.
8dcc
·2 lata temu·discuss
> The diagrams in particular are very clear. (They seem to have been done in draw.io: https://github.com/8dcc/8dcc.github.io/blob/main/img/pool-al... which seems to be a pretty decent Apache-2.0 free software licensed diagram editor: https://github.com/jgraph/drawio/)

Yes, this is true. Furthermore, the diagram information for draw.io is included in the SVG images themselves, so one could edit them there.

> It says, "The pool allocator, however, is much faster than malloc", but doesn't provide any benchmarks or even an order of magnitude.

You are right, I was referring to "malloc-like" allocators (i.e. for variable-size blocks). It would be a good idea to benchmark them.
8dcc
·2 lata temu·discuss
Hello, I am the author. Thank you all for the instructive comments, I made some changes to the article since I first posted it:

- Added a link to this HN post.

- Renamed some variables and types in the code for readability.

- Mention (in a footnote) that we could allocate the 'Pool' structure and the chunk arrays with a single call, or even return the 'Pool' on the stack. Suggested by 'liontwist' and 'unwind'.

- Mention (in a footnote) that we don't always need to store the full address when building the linked list of free chunks. Suggested by 'cb321'.

- Added valgrind support (also to my 'libpool' project). Suggested by 'kazinator'.
8dcc
·2 lata temu·discuss
Thank you so much! I will definitely check it out. I also planned on writing an article about arena allocators soon.
8dcc
·2 lata temu·discuss
I have never heard about this (using valgrind with a "non-standard allocator"), but it looks really interesting, specially for other projects I am working on. I will definitely look into it.
8dcc
·2 lata temu·discuss
I don't currently have much experience with thread safety, but it's something I should look into. Thank you.
8dcc
·2 lata temu·discuss
I will also take note of this, you are right.
8dcc
·2 lata temu·discuss
Yes, this is true. I didn't use that in the code because I thought it would make it less readable, though. I might mention it somewhere, thank you.