foonathan / memory

STL compatible C++ memory allocator library using a new RawAllocator concept that is similar to an Allocator but easier to use and write.
https://memory.foonathan.net
zlib License
1.48k stars 189 forks source link

memory_pool_collection fails to allocate memory #173

Closed cohdan closed 8 months ago

cohdan commented 10 months ago

Hi, I have the following code:

using memory_pool = foonathan::memory::memory_pool_collection<memory::node_pool,
                                             memory::identity_buckets,
                                             memory::fixed_block_allocator<memory::default_allocator>>;

class something {
public:
    void init();
private:
   unique_ptr<memory_pool>     _object_pool;
}

void something::init() {
   size_to_allocate = 1024*1024;

    initializer_list<size_t> node_sizes = {memory::list_node_size<pair<init, int>>::value,
                                           memory::unordered_map_node_size<int, list<pair<int,int>>::iterator>::value,
                                           sizeof(memory::unordered_map<int, list<pair<int,int>>::iterator>::iterator)};
    auto max_node_size = std::max(node_sizes);

    _object_pool = make_unique<memory_pool>(max_node_size, size_to_allocate);
    _object_pool->allocate_node(32);
}

When executing this code an exception is thrown:

[foonathan::memory] Allocator foonathan::memory::fixed_block_allocator (at 0x600001ed4158) ran out of memory trying to allocate 0 bytes.

Tried also to replace the _object_pool->allocate_node(32); with _object_pool->get_allocator().allocate_block(); and got the same exception.

This is a simplification of the code that I want to achieve at the end which is using this pool collection for a couple of containers (one list and one map as can be seen). My understanding is that the pool collection will allocate the block in the first call for allocate_node/allocate_array - but seems like this is not the case. How am I supposed to trigger the actual memory allocation? Or am I completely off?

Thanks.

cohdan commented 10 months ago

It seems like the fixed block allocator does not work with memory pool collection - when I changed it to the growing block allocator all seems to work fine. I'd think that there shouldn't be a reason for the fixed allocator not to work in this case, am I wrong? Anyway, I continue to look into this because I do need a fixed allocator and I do need several node sizes. Will be happy if anyone can still help. Thanks.

cohdan commented 9 months ago

so the issue is that the memory pool collection always looks at the next block size when assigning memory to a bucket (free list) which will not work with fixed buffer as fixed buffer allocates the block in the creation of the object and then next block will always be 0.

@foonathan is this an intended behavior or a bug? Thanks.

cohdan commented 9 months ago

In the meantime I wrote a wrppar class to the fixed allocator that returns the allocated block_size in next_block_size (instead of zero) and it seems to work fine.

template<class RawAllocator = memory::default_allocator>
    class fixed_block_allocator_for_memory_pool_collection {

    public:
        using allocator_type = memory::traits_detail::allocator_type<RawAllocator>;
        explicit fixed_block_allocator_for_memory_pool_collection(std::size_t block_size) noexcept
                                                                  : _underline_allocator(block_size, allocator_type()), _block_size(block_size) {}

        memory::memory_block allocate_block() {
            return _underline_allocator.allocate_block();
        }

        void deallocate_block(memory::memory_block block) noexcept {
            _underline_allocator.deallocate_block(block);
        }

        allocator_type& get_allocator() noexcept
        {
            return _underline_allocator.get_allocator();
        }

        std::size_t next_block_size() const noexcept {
            return _block_size;
        }

    private:
        size_t                                          _block_size;
        memory::fixed_block_allocator<RawAllocator>     _underline_allocator;
    };

Please let me know if this is something that you would like me to upload as a PR.

foonathan commented 8 months ago

I've changed memory_pool_collection to use the current block size instead, which should also solve the problem.