Boost logo

Boost Users :

Subject: Re: [Boost-users] Zero-malloc memory pool for Boost Intrusive smart pointers
From: Gavin Lambert (boost_at_[hidden])
Date: 2019-03-22 21:40:10


At 09:25 23/03/2019, Francesco wrote:
>Yes I know about std::make_shared<> and indeed I
>was using that solution before implementing the
>memory pool based on intrusive pointers.
>The problem is that in my workload I have
>several threads that need to get a smart pointer
>to a fairly-big object every time they process
>input data and they will release it later.

Which brings up another point; your current
implementation is not thread-safe. Which is
fine, but you should probably mention that
explicitly in your readme. A very common worker
pattern is to have all allocations on one thread
and all deallocations on another thread, and that
wouldn't work as-is.

>Now allocating with std::make_shared<>Â a new
>object on every input data was causing my
>threads to do lots of mallocs/sec and that
>became the performace limiting factor.
>The use of a memory pool instead allows me to do
>a very large memory allocation from time to time
>(in blocks of e.g. 1024 items) and still have
>each single item of the memory pool independently refcounted.

Yes, I realise that. It still could be possible
to have individual node allocations strung up
into a free list rather than requiring a larger
contiguous allocation. But you're correct that
arena allocation and intrusive_ptr is probably
more efficient in the end.

>My first implementation of the memory pool
>indeed was using C++11 perfect forwarding to
>call the ctor/dtor of type T when the item was
>pulled out the pool or was returning to it.
>I later removed such feature because I realized
>that calling the ctor of the items to recycle
>produced issues with classes having multiple inheritance IIRC.
>I don't think it's safe and sane to call the
>ctor of the same instance multiple times...Â

Calls must be paired -- you allocate aligned
uninitialised storage (aligned_storage), then
placement-new to call the constructor on that
storage, then eventually call the destructor, and
then later you can placement-new again.

You must never call the constructor twice in a
row or the destructor twice in a row (unless it's
trivial), but alternating is fine.

Again, this is how things like optional and
variant work internally -- and since they do that
part for you, it can be useful to re-use it
rather than re-implementing it.


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net