STL compatible C++ memory allocator library using a new RawAllocator concept that is similar to an Allocator but easier to use and write.

memory

Project Status Build Status Code Coverage

The C++ STL allocator model has various flaws. For example, they are fixed to a certain type, because they are almost necessarily required to be templates. So you can't easily share a single allocator for multiple types. In addition, you can only get a copy from the containers and not the original allocator object. At least with C++11 they are allowed to be stateful and so can be made object not instance based. But still, the model has many flaws. Over the course of the years many solutions have been proposed, for example EASTL. This library is another. But instead of trying to change the STL, it works with the current implementation.

Sponsored by Embarcadero C++Builder.

If you like this project, consider supporting me.

Features

New allocator concepts:

  • a RawAllocator that is similar to an Allocator but easier to use and write
  • a BlockAllocator that is an allocator for huge memory blocks

Several implementations:

  • heap_/malloc_/new_allocator
  • virtual memory allocators
  • allocator using a static memory block located on the stack
  • memory stack, iteration_allocator
  • different memory pools
  • a portable, improved alloca() in the form of temporary_allocator
  • facilities for joint memory allocations: share a big memory block for the object and all dynamic memory allocations for its members

Adapters, wrappers and storage classes:

  • incredible powerful allocator_traits allowing Allocators as RawAllocators
  • std_allocator to make a RawAllocator an Allocator again
  • adapters for the memory resource TS
  • allocator_deleter classes for smart pointers
  • (optionally type-erased) allocator_reference and other storage classes
  • memory tracking wrapper

In addition:

  • container node size debuggers that obtain information about the node size of an STL container at compile-time to specify node sizes for pools
  • debugging options for leak checking, double-free checks or buffer overflows
  • customizable error handling routines that can work with exceptions disabled
  • everything except the STL adapters works on a freestanding environment

Basic example

#include <algorithm>
#include <iostream>
#include <iterator>

#include <foonathan/memory/container.hpp> // vector, list, list_node_size
#include <foonathan/memory/memory_pool.hpp> // memory_pool
#include <foonathan/memory/smart_ptr.hpp> // allocate_unique
#include <foonathan/memory/static_allocator.hpp> // static_allocator_storage, static_block_allocator
#include <foonathan/memory/temporary_allocator.hpp> // temporary_allocator

// alias namespace foonathan::memory as memory for easier access
#include <foonathan/memory/namespace_alias.hpp>

template <typename BiIter>
void merge_sort(BiIter begin, BiIter end);

int main()
{
    using namespace memory::literals;

    // a memory pool RawAllocator
    // allocates a memory block - initially 4KiB - and splits it into chunks of list_node_size<int>::value big
    // list_node_size<int>::value is the size of each node of a std::list
    memory::memory_pool<> pool(memory::list_node_size<int>::value, 4_KiB);

    // just an alias for std::list<int, memory::std_allocator<int, memory::memory_pool<>>
    // a std::list using a memory_pool
    // std_allocator stores a reference to a RawAllocator and provides the Allocator interface
    memory::list<int, memory::memory_pool<>> list(pool);
    list.push_back(3);
    list.push_back(2);
    list.push_back(1);

    for (auto e : list)
        std::cout << e << ' ';
    std::cout << '\n';

    merge_sort(list.begin(), list.end());

    for (auto e : list)
        std::cout << e << ' ';
    std::cout << '\n';

    // allocate a std::unique_ptr using the pool
    // memory::allocate_shared is also available
    auto ptr = memory::allocate_unique<int>(pool, *list.begin());
    std::cout << *ptr << '\n';

    // static storage of size 4KiB
    memory::static_allocator_storage<4096u> storage;

    // a memory pool again but this time with a BlockAllocator
    // this controls the internal allocations of the pool itself
    // we need to specify the first template parameter giving the type of the pool as well
    // (node_pool is the default)
    // we use a static_block_allocator that uses the static storage above
    // all allocations will use a memory block on the stack
    using static_pool_t = memory::memory_pool<memory::node_pool, memory::static_block_allocator>;
    static_pool_t static_pool(memory::unordered_set_node_size<int>::value, 4096u, storage);

    // again, just an alias for std::unordered_set<int, std::hash<int>, std::equal_to<int>, memory::std_allocator<int, static_pool_t>
    // see why I wrote these? :D
    // now we have a hash set that lives on the stack!
    memory::unordered_set<int, static_pool_t> set(static_pool);

    set.insert(3);
    set.insert(2);
    set.insert(3); // running out of stack memory is properly handled, of course

    for (auto e : set)
        std::cout << e << ' ';
    std::cout << '\n';
}

// naive implementation of merge_sort using temporary memory allocator
template <typename BiIter>
void merge_sort(BiIter begin, BiIter end)
{
    using value_type = typename std::iterator_traits<BiIter>::value_type;

    auto distance = std::distance(begin, end);
    if (distance <= 1)
        return;

    auto mid = begin;
    std::advance(mid, distance / 2);

    // an allocator for temporary memory
    // is similar to alloca() but uses its own stack
    // this stack is thread_local and created on the first call to this function
    // as soon as the allocator object goes out of scope, everything allocated through it, will be freed
    auto alloc = memory::make_temporary_allocator();

    // alias for std::vector<value_type, memory::std_allocator<value_type, memory::temporary_allocator>>
    // a std::vector using a temporary_allocator
    memory::vector<value_type, memory::temporary_allocator> first(begin, mid, alloc),
                                                            second(mid, end, alloc);

    merge_sort(first.begin(), first.end());
    merge_sort(second.begin(), second.end());
    std::merge(first.begin(), first.end(), second.begin(), second.end(), begin);
}

See example/ for more.

Installation

This library can be used as CMake subdirectory. It is tested on GCC 4.8-5.0, Clang 3.5 and Visual Studio 2013. Newer versions should work too.

  1. Fetch it, e.g. using git submodules git submodule add https://github.com/foonathan/memory ext/memory and git submodule update --init --recursive.

  2. Call add_subdirectory(ext/memory) or whatever your local path is to make it available in CMake.

  3. Simply call target_link_libraries(your_target PUBLIC foonathan_memory) to link this library and setups the include search path and compilation options.

You can also install the library:

  1. Run cmake -DCMAKE_BUILD_TYPE="buildtype" -DFOONATHAN_MEMORY_BUILD_EXAMPLES=OFF -DFOONATHAN_MEMORY_BUILD_TESTS=OFF . inside the library sources.

  2. Run cmake --build . -- install to install the library under ${CMAKE_INSTALL_PREFIX}.

  3. Repeat 1 and 2 for each build type/configuration you want to have (like Debug, RelWithDebInfo and Release or custom names).

To use an installed library:

  1. Call find_package(foonathan_memory major.minor REQUIRED) to find the library.

  2. Call target_link_libraries(your_target PUBLIC foonathan_memory) to link to the library and setup all required options.

See https://memory.foonathan.net/md_doc_installation.html for a detailed guide.

Documentation

Full documentation can be found at https://memory.foonathan.net/.

A tutorial is also available at https://memory.foonathan.net/md_doc_tutorial.html.

RawAllocator

Below is the interface required for a RawAllocator, everything optional is marked:

struct raw_allocator
{
    using is_stateful = std::integral_constant<bool, Value>; // optional, defaults to std::is_empty

    void* allocate_node(std::size_t size, std::size_t alignment); // required, allocation function
    void deallocate_node(void *node, std::size_t size, std::size_t alignment) noexcept; // required, deallocation function

    void* allocate_array(std::size_t count, std::size_t size, std::size_t alignment); // optional, forwards to node version
    void deallocate_array(void *ptr, std::size_t count, std::size_t size, std::size_t alignment) noexcept; // optional, forwards to node version

    std::size_t max_node_size() const; // optional, returns maximum value
    std::size_t max_array_size() const; // optional, forwards to max_node_size()
    std::size_t max_alignment() const; // optional, returns maximum fundamental alignment, i.e. alignof(std::max_align_t)
};

A RawAllocator only needs to be moveable, all Allocator classes are RawAllocators too. Classes not providing the interface can specialize the allocator_traits, read more about writing allocators here or about the technical details of the concept here.

Acknowledgements

This project is greatly supported by my patrons. In particular thanks to the individual supporters:

  • Kaido Kert

And big thanks to the contributors as well:

  • @asobhy-qnx
  • @bfierz
  • @nicolastagliani
  • @cho3
  • @j-carl
  • @myd7349
  • @moazzamak
  • @maksqwe
  • @kaidokert
  • @gabyx
  • @maksqwe
  • @Manu343726
  • @MiguelCompany
  • @moazzamak
  • @myd7349
  • @quattrinili
  • @razr
  • @seanyen
  • @wtsnyder
  • @zhouchengming1
Owner
Jonathan Müller
Interested in C++, I write libraries and blog about them.
Jonathan Müller
Comments
  • cross compiling for QNX segfaults

    cross compiling for QNX segfaults

    When cross compile master on QNX, I get a segmentation fault from container_node_sizes_impl.hpp

    CMake command with toolchain: qnx_toolchain.zip

    cmake .. -DCMAKE_TOOLCHAIN_FILE=~/Downloads/qnx_toolchain.cmake -DCMAKE_INSTALL_PREFIX=/home/brian/qnx700/target/qnx7/x86/usr/local -DCMAKE_BUILD_TYPE=Release -DCMAKE_VERBOSE_MAKEFILE=ON -DFOONATHAN_MEMORY_BUILD_EXAMPLES=OFF -DFOONATHAN_MEMORY_BUILD_TESTS=OFF -DFOONATHAN_MEMORY_BUILD_TOOLS=ON

    Output: [ 13%] Generating container_node_sizes_impl.hpp cd /home/brian/Downloads/foonathan_memory/build/src && ../tool/nodesize_dbg --code --alignof "FOONATHAN_ALIGNOF(T)" /home/brian/Downloads/foonathan_memory/build/src/container_node_sizes_impl.hpp Segmentation fault (core dumped) src/CMakeFiles/foonathan_memory.dir/build.make:64: recipe for target 'src/container_node_sizes_impl.hpp' failed make[2]: *** [src/container_node_sizes_impl.hpp] Error 139 make[2]: Leaving directory '/home/brian/Downloads/foonathan_memory/build' CMakeFiles/Makefile2:88: recipe for target 'src/CMakeFiles/foonathan_memory.dir/all' failed make[1]: *** [src/CMakeFiles/foonathan_memory.dir/all] Error 2 make[1]: Leaving directory '/home/brian/Downloads/foonathan_memory/build' Makefile:132: recipe for target 'all' failed make: *** [all] Error 2 build_output.txt

  • Mcross/cmake node size

    Mcross/cmake node size

    Hi Jonathan,

    I got bit by an issue in eProsima's FastRTPS that uses this library when it was cross compiled. When your "node size debugger" didn't run, it had its own logic that happened to be broken on 64-bit ARM with a recent C++ library. We fixed the issue, but it occurred to me that it would be great if your library could provide this information directly even when it was cross compiled.

    I remembered a technique proposed by Scott Meyers in one of his Effective C++ books when debugging what types were generated in templates - put the type in a context that would generate an error and the compiler will tell you what type it generated. Therefore I could get the C++ compiler to tell me in an error message values it could calculate at compile time: like the sizes and alignments of types. I tried it on every C++ compiler on Compiler Explorer, and saw that every compiler put calculated numbers in the generated type name even though some would put calculated sub-types in separate lines.

    In the end, this uses compiler error messages and some logic in CMake to generate the container_node_sizes_impl.hpp file even when cross-compiling, without requiring an emulator or manually running the debug tool on target hardware.

    Let me know what you think.

    -Matt Cross
    
  • How to estimate size of static memory block correctly?

    How to estimate size of static memory block correctly?

    I'm trying to use a static memory block with a memory_pool to be the allocator for an std::list.

    For example:

    using DataType = std::shared_ptr<void>;
    
    using MemoryPool =
        foonathan::memory::memory_pool<foonathan::memory::node_pool, foonathan::memory::static_block_allocator>;
    
    constexpr size_t pool_capacity    = 20;
    constexpr size_t node_size_bytes  = list_node_size<DataType>::value;
    constexpr size_t block_size_bytes = MemoryPool::min_block_size( node_size_bytes, pool_capacity );
    
    INFO( "alignof(DataType) = " << alignof(DataType) );
    INFO( "sizeof(DataType) = " << sizeof(DataType) );
    INFO( "pool_capacity = " << pool_capacity );
    INFO( "node_size_bytes = " << node_size_bytes );
    INFO( "block_size_bytes = " << block_size_bytes );
    
    foonathan::memory::static_allocator_storage<block_size_bytes> storage;
    MemoryPool memoryPool( node_size_bytes, block_size_bytes, storage );
    
    using Allocator = foonathan::memory::std_allocator<DataType, MemoryPool>;
    using Container = std::list<DataType, Allocator>;
    
    Container container{ Allocator{ memoryPool } };
    
    for ( int count = 0; count < static_cast<int>(pool_capacity); ++count ) {
        INFO( "adding item " << count );
        container.emplace_back( std::make_shared<int>( count ) );
    }
    CHECK( container.size() == pool_capacity );
    

    So this code on both MSVC x64 and AppleClang x64 reports:

      alignof(DataType) = 8
      sizeof(DataType) = 16
      pool_capacity = 20
      node_size_bytes = 32
      block_size_bytes = 656
    

    which looks fine. On clang runs with no problems. But on MSVC it runs out of memory trying to add the 16th item, asking to allocate another block of size 656

    I was hoping there was some guidance we can use to estimate the required sizes correctly? Using some other diagnostics (a memory counting allocator), it appears the overhead of std::list in MSVCRT is slightly higher than libc++

    Thank you

  • How to use memory::unordered_map

    How to use memory::unordered_map

    Hey, first off thanks for the library, it's been extremely helpful so far.

    I'm a new user and looking to use memory::unordered_map<int64_t, float*, memory::memory_pool<>>, but I think I'm having trouble initializing the memory pool to use here because I consistently get an error like the following upon first insertion:

    [foonathan::memory] Allocator foonathan::memory::memory_pool (at 0x141908a00) received invalid size/alignment 32, max supported is 16
    

    The relevant code I have so far is:

    memory::memory_pool<> pool (memory::unordered_map_node_size<int64_t>::value, 2048);
    memory::unordered_map<int64_t, float*, memory::memory_pool<>> map (pool);
    

    And then the first insertion throws the above error. I've tried templating unordered_map_node_size with std::pair<int64_t, float*> as well with no luck.

    What am I doing wrong here?

    Thanks

  • Fix cmake crosscompiling

    Fix cmake crosscompiling

    This fix allows foonathan/memory to build correctly with all nodesize features when crosscompiling. It builds the nodesize_dbg tool and links it statically to avoid anoying library search paths. Then it uses the crosscompiling emulator provided by the toolchain file to run nodesize_dbg and generate container_node_sizes_impl.hpp during the build.

    For this to work the toolchain file must provide the emulator executable

    Example aarch64-linux-gnu.cmake toolchain file

    # 64 bit ARM (aarch64)
    
    # use it like this:
    # cmake -DCMAKE_TOOLCHAIN_FILE=/path/to/toolchain.cmake <sourcedir>
    
    # set the name of the target system
    set(CMAKE_SYSTEM_NAME "Linux" CACHE STRING "Target system")
    set(CMAKE_SYSTEM_PROCESSOR "aarch64" CACHE STRING "Target architecture")
    
    # set the compiler
    set(CMAKE_LIBRARY_ARCHITECTURE "aarch64-linux-gnu")
    set(CMAKE_C_COMPILER   "${CMAKE_LIBRARY_ARCHITECTURE}-gcc")
    set(CMAKE_CXX_COMPILER "${CMAKE_LIBRARY_ARCHITECTURE}-g++")
    set(CMAKE_LINKER       "${CMAKE_LIBRARY_ARCHITECTURE}-ld")
    
    # where is the target environment located
    # this should be a chroot environment on your system with all the required native libraries
    set(CMAKE_FIND_ROOT_PATH "/usr/local/targets/${CMAKE_LIBRARY_ARCHITECTURE}")
    include_directories("${CMAKE_FIND_ROOT_PATH}/usr/include/${CMAKE_LIBRARY_ARCHITECTURE}")
    
    # adjust the default behaviour of the FIND_XXX() commands:
    # search for programs in the host environment
    # search for headers and libraries in the target environment 
    set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
    set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
    set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
    
    # crosscompiling emulator ( cmake > 3.4 )
    # This variable is only used when CMAKE_CROSSCOMPILING is on.
    # It should point to a command on the host system that can run
    # executables built for the target system. The command will also be
    # used to run try_run() generated executables, which avoids 
    # manual population of the TryRunResults.cmake file.
    # It is also used as the default value for the CROSSCOMPILING_EMULATOR
    # target property of executables.
    
    # not required on x86_64 systems running i386 code
    
    set(CMAKE_CROSSCOMPILING_EMULATOR /usr/bin/qemu-${CMAKE_SYSTEM_PROCESSOR})
    
  • nullptr as unique_ptr with Deleter

    nullptr as unique_ptr with Deleter

    I have the following problem: I have a class BinaryBuffer which should have a default Ctor:

    using Deleter     = foonathan::memory::allocator_deleter<uint8_t[], RawAllocator>;
    using BufferPtr  = std::unique_ptr<uint8_t[], Deleter>;
    
    //! Constructor for an empty buffer!
        BinaryBuffer(std::shared_ptr<RawAllocator> allocator)
            : m_allocator(allocator)
            , m_data(nullptr, Deleter{foonathan::memory::make_allocator_reference(*allocator), 0})
        {}
    

    It takes a RawAllocator which it keeps as reference (m_allocator). The data m_data is of type BufferPtr. My problem I am facing is, that I need a valid allocator smart pointer (not nullptr) such that I can setup the Deleter, even if the pointer is actually nullptr. Is there a way of having a default CTOR where I set the m_data member to nullptr, with an invalid deleter. Is there such a wrapper like make_allocator_pointer(allocator.get()) which wraps a pointer to the allocator internally which I can default to nullptr. Or can this be achieved similarly?

  • Fixed memory_pool::min_block_size calculation

    Fixed memory_pool::min_block_size calculation

    Previously, memory_pool::min_block_size() would not compute true node size in the same way that the individual free list implementations did. For instance, ordered_free_memory_list uses 2*node_size as debug fence memory, which memory_pool was disregarding. This could result in a failure at runtime, if the block was too small for a full node, including debug fences.

    Now, each free_list impl exposes "actual_node_size(n)", which produces the true required size, given the requested node size. This function is the same as what's used in the real internal size computations.

    Also hoisted fence_size() into constexpr functions in each free_list implementation, as well as added an "adjusted_node_size" function, which is mainly for readability, to avoid having "x > y ? x : y" repeated.

    Test added to exercise the bug.

    Addresses issue #109

  • [foonathan::memory] Allocator foonathan::memory::memory_pool (at 0x559f6319a8) received invalid size/alignment 56, max supported is 48terminate called after throwing an instance of 'foonathan::memory::bad_node_size'   what():  allocation node size exceeds supported maximum of allocator

    [foonathan::memory] Allocator foonathan::memory::memory_pool (at 0x559f6319a8) received invalid size/alignment 56, max supported is 48terminate called after throwing an instance of 'foonathan::memory::bad_node_size' what(): allocation node size exceeds supported maximum of allocator

    The -DFOONATHAN_MEMORY_CONTAINER_NODE_SIZES_IMPL is only applicable to QNX platform and so passing this flag was not effective. The node size info was not used by memory and caused FastDDS to use custom node size implementation. The segfault occurs at line 230 of RTPSReader.cpp for the map<GUID_t, uint16_t> object.

    The fix was simple, manually copy container_node_sizes_impl.hpp to src/ under the build directory.

    Originally posted by @rushipatel in https://github.com/foonathan/memory/issues/103#issuecomment-828119581

  • which pool to use for dynamic sizes

    which pool to use for dynamic sizes

    Is it possible to have a memory collection (log2 buckets) which has no maxnode size? I have to following scenario, I receive binary message and I would like to have memory pool which provides me a char buffer for this binary messages. However I have no idea about the maximum size of the message. It can be that they are always below lets say 16kb and suddenly a message needs a buffer of 4mb. Can that be done with your pool collection? Probably I misunderstand something here:

    From the tests I see:

    memory_pool_collection<node_pool, identity_buckets, allocator_reference<test_allocator>>;
        test_allocator alloc;
        {
            const auto max_size = 16u;
            pools      pool(max_size, 1000, alloc);
    

    meaning we have a block size of 1000bytes and the maximum node size (my buffer size) is fixed to 16bytes... So when I request 17bytes what happens?

    Thanks a lot =)

  • Strange exception from unordered_set with memory_stack, on MSVC

    Strange exception from unordered_set with memory_stack, on MSVC

    With the Microsoft compiler (I'm using VC19, but I imagine it's the same for others), and with fairly simple usage of std::unordered_set with a memory_stack allocator, I get an exception coming from inside the STL.

    I believe it is related to the extra implementation_offset reserved by foonathan.

    I'm not sure if this represents a bug in the MSVC STL, a bug in foonathan::memory, or if this is some expected limitation.

    Below is a simple failing test. The insert() line will throw std::length_error with message invalid hash bucket count.

    TEST_CASE("std unordered_set problem on MSVC") {
        using memory_stack_t = foonathan::memory::memory_stack<>;
        memory_stack_t myAlloc(1024);
        using MySet = foonathan::memory::unordered_set<int, memory_stack_t>;
        MySet mySet(myAlloc);
        for (int i = 0; i < 1000; ++i) {
            mySet.insert(i);
        }
    }
    

    This is the line in the STL that generates the error: https://github.com/microsoft/STL/blob/2f8342a3a57fb157d881c6a2d42a917d20e413f8/stl/inc/xhash#L1717

    Feel free to step through it yourself, but my brief summary:

    • inserting enough items causes a re-hash
    • the STL code seems to assume that a next-larger-power-of-2 size number of buckets will be available
    • the allocator's max_size comes back as slightly smaller than a power of 2, because of implementation_offset
    • this causes the STL code to round it down to the next lower power of 2 (see _Floor_of_log_2(...))
    • this causes it to raise the exception, since the number of buckets it wants is not in agreement with the buckets available.

    In particular, there is this comment:

    // Don't violate power of 2, fits in half the bucket vector invariant:
    // (we assume because vector must use single allocations; as a result, its max_size fits in a size_t)
    

    I am not sure if this invariant is somehow guaranteed by the C++ standard, or is just an assumption made in the MSVC STL. It all works fine on glibc, for what that's worth.

    I wonder if the implementation_offset amount should be something in addition to the basic grow-by-doubling calculation, rather than eating into it, slightly?

  • Runtime error: 'allocation node size exceeds supported maximum of allocator'

    Runtime error: 'allocation node size exceeds supported maximum of allocator'

    When I run my cross-compiled fastrtps application on the aarch64 linux platform, I see following exception

    [foonathan::memory] Allocator foonathan::memory::memory_pool (at 0x559f6319a8) received invalid size/alignment 56, max supported is 48terminate called after throwing an instance of 'foonathan::memory::bad_node_size'
      what():  allocation node size exceeds supported maximum of allocator
    Aborted
    

    I have used file container_node_sizes_impl.hpp generated by nodesize_dbg on target platform. The output of the nodesize_dbg from target platform is as following

    forward_list:
    	1=15
    	2=14
    	4=12
    	8=8
    	16=16
    list:
    	1=23
    	2=22
    	4=20
    	8=16
    	16=16
    set:
    	1=39
    	2=38
    	4=36
    	8=32
    	16=32
    multiset:
    	1=39
    	2=38
    	4=36
    	8=32
    	16=32
    unordered_set:
    	1=23
    	2=22
    	4=20
    	8=16
    	16=32
    unordered_multiset:
    	1=23
    	2=22
    	4=20
    	8=16
    	16=32
    map:
    	1=38
    	2=36
    	4=32
    	8=32
    	16=32
    multimap:
    	1=38
    	2=36
    	4=32
    	8=32
    	16=32
    unordered_map:
    	1=22
    	2=20
    	4=16
    	8=16
    	16=32
    unordered_multimap:
    	1=22
    	2=20
    	4=16
    	8=16
    	16=32
    shared_ptr_stateless:
    	1=24
    	2=24
    	4=24
    	8=24
    	16=32
    shared_ptr_stateful:
    	1=32
    	2=32
    	4=32
    	8=32
    	16=48
    

    Build method

    # 1) Cross-compile `nodesize_dbg`, run it on the target and get `container_node_sizes_impl.hpp`
    # 2) Cross-compile memory
      cmake \
        -DFOONATHAN_MEMORY_CONTAINER_NODE_SIZES_IMPL=./container_node_sizes_impl.hpp \
        -DCMAKE_TOOLCHAIN_FILE="/code/cross_compile/linux_toolchain.cmake" \
        ..
    

    Toolchain file

    set(CMAKE_SYSTEM_PROCESSOR "aarch64")
    set(CMAKE_C_COMPILER "/usr/bin/aarch64-linux-gnu-gcc-7")
    set(CMAKE_CXX_COMPILER "/usr/bin/aarch64-linux-gnu-g++-7")
    set(CMAKE_FIND_ROOT_PATH "/usr/aarch64-linux-gnu")
    set(CMAKE_SYSTEM_NAME Linux)
    set(CMAKE_HOST_LINUX ON)
    set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
    set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
    set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
    set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
    
  • [docs/examples] associative containers

    [docs/examples] associative containers

    Looking through the code and docs it's not very clear that the assoc_container_node_size templates require an std::pair<K,V> as both template parameters are just called T and the docs don't give any insights about T. If it doesn't break the implementation_defined trickery/tooling maybe renaming to KV would help as well. Not passing an std::pair for these containers probably shouldn't even be allowed to compile tbh.

    Also I haven't found any examples on how to use these containers. Currently searching for (IIRC any) of the assoc_container_node_size yields no results apart from their definitions.

    Maybe adding an example of all containers being used in conjunction with the container_node_size would be a good addition. I'm happy to help with that if wanted.

  • `memory_pool_collection` carves too little memory from block if there are many buckets

    `memory_pool_collection` carves too little memory from block if there are many buckets

    Basically, this:

    const size_t max_node_size = 512 * 1024 * 1024;
    const size_t block_size = 1024 * 1024 * 1024;
    memory::memory_pool_collection<memory::node_pool, memory::log2_buckets> my_pool(max_node_size, block_size);
    my_pool.allocate_node(256 * 1024 * 1024);
    

    This fails FOONATHAN_MEMORY_ASSERT(no_nodes > 0); in free_list.cpp because memory_pool_collection::def_capacity() returns arena._next_block_size() / pools_.size(), i.e., 2147483632 / 27 = 79536430, which is less than the requested 268435456.

  • Moving containers with their memory pools

    Moving containers with their memory pools

    This is more of a question than an issue, and potentially a feature request.

    I have a class managing a kind of a graph data structure, where standard containers (maps and lists) are used to store relationships between the graph elements, and a foonathan/memory is used with a memory_pool to avoid allocation overhead.

    The managing class "owns" the tree and is therefore also holding the memory_pools. I have naively assumed that a defaulted move constructor would "do the right thing (TM)", but it leads to nasty segmentation faults. As far as I can tell, the move constructor for the pool moves the ownership of the memory as expected, and the move constructor for the containers do transfer ownership of the nodes within the moved memory correctly too. However, the moved stl_allocator will keep a pointer to the original memory_pool object, which does not own the memory of the nodes anymore.

    Is there a way to make this work, perhaps with an explicit update of the std_allocator (unlikely, not designed for in the STL), or potentially with a different allocator?

  • Document basic concepts

    Document basic concepts

    In addition to memory-specific concepts already described in docs, it would be useful to describe basic concepts of memory management, such as allocator, arena, pool, etc. This would make the library design easier to understand by newcomers. Also this clarifies the nomenclature used by the library and its docs.

MMCTX (Memory Management ConTeXualizer), is a tiny (< 300 lines), single header C99 library that allows for easier memory management by implementing contexts that remember allocations for you and provide freeall()-like functionality.

MMCTX (Memory Management ConTeXualizer), is a tiny (< 300 lines), single header C99 library that allows for easier memory management by implementing contexts that remember allocations for you and provide freeall()-like functionality.

Oct 2, 2021
The Hoard Memory Allocator: A Fast, Scalable, and Memory-efficient Malloc for Linux, Windows, and Mac.

The Hoard Memory Allocator Copyright (C) 1998-2020 by Emery Berger The Hoard memory allocator is a fast, scalable, and memory-efficient memory allocat

Jan 2, 2023
Mesh - A memory allocator that automatically reduces the memory footprint of C/C++ applications.
Mesh - A memory allocator that automatically reduces the memory footprint of C/C++ applications.

Mesh: Compacting Memory Management for C/C++ Mesh is a drop in replacement for malloc(3) that can transparently recover from memory fragmentation with

Dec 30, 2022
Malloc Lab: simple memory allocator using sorted segregated free list

LAB 6: Malloc Lab Main Files mm.{c,h} - Your solution malloc package. mdriver.c - The malloc driver that tests your mm.c file short{1,2}-bal.rep - T

Feb 28, 2022
Public domain cross platform lock free thread caching 16-byte aligned memory allocator implemented in C
Public domain cross platform lock free thread caching 16-byte aligned memory allocator implemented in C

rpmalloc - General Purpose Memory Allocator This library provides a public domain cross platform lock free thread caching 16-byte aligned memory alloc

Dec 28, 2022
A tiny portable C89 memory allocator

mem A tiny portable C89 memory allocator. Usage This is a single-header library. You must include this file alongside #define MEM_IMPLEMENTATION in on

Nov 20, 2022
Allocator bench - bench of various memory allocators

To run benchmarks Install lockless from https://locklessinc.com/downloads/ in lockless_allocator path make Install Hoard from https://github.com/emery

Dec 4, 2022
A simple windows driver that can read and write to process memory from kernel mode

ReadWriteProcessMemoryDriver A simple windows driver that can read and write to process memory from kernel mode This was just a small project for me t

Dec 7, 2022
Custom memory allocators in C++ to improve the performance of dynamic memory allocation
Custom memory allocators in C++ to improve the performance of dynamic memory allocation

Table of Contents Introduction Build instructions What's wrong with Malloc? Custom allocators Linear Allocator Stack Allocator Pool Allocator Free lis

Jan 2, 2023
Memory-dumper - A tool for dumping files from processes memory

What is memory-dumper memory-dumper is a tool for dumping files from process's memory. The main purpose is to find patterns inside the process's memor

Nov 9, 2022
mimalloc is a compact general purpose allocator with excellent performance.
mimalloc is a compact general purpose allocator with excellent performance.

mimalloc mimalloc (pronounced "me-malloc") is a general purpose allocator with excellent performance characteristics. Initially developed by Daan Leij

Dec 30, 2022
Hardened malloc - Hardened allocator designed for modern systems

Hardened malloc - Hardened allocator designed for modern systems. It has integration into Android's Bionic libc and can be used externally with musl and glibc as a dynamic library for use on other Linux-based platforms. It will gain more portability / integration over time.

Jan 3, 2023
Snmalloc - Message passing based allocator

snmalloc snmalloc is a high-performance allocator. snmalloc can be used directly in a project as a header-only C++ library, it can be LD_PRELOADed on

Jan 9, 2023
Using shared memory to communicate between two executables or processes, for Windows, Linux and MacOS (posix). Can also be useful for remote visualization/debugging.

shared-memory-example Using shared memory to communicate between two executables or processes, for Windows, Linux and MacOS (posix). Can also be usefu

Aug 17, 2022
Execute MachO binaries in memory using CGo

Execute Thin Mach-O Binaries in Memory This is a CGo implementation of the initial technique put forward by Stephanie Archibald in her blog, Running E

Dec 2, 2022
Fast C++ IPC using shared memory

Fast C++ IPC using shared memory

Dec 14, 2022
A simple C++ library for creating and managing bitstreams in memory.

ezbitstream (v0.001) A simple C++ library for creating and managing bitstreams in memory. API & Implementation ezbitstream implements bitstreams with

Feb 4, 2022
Modern C++ 32bit Windows Process Memory Library.
Modern C++ 32bit Windows Process Memory Library.

basil Simple 32-bit Windows Process Memory Library. Written in Modern C++. JavaScript bindings basil (wilL) be available as bindings for JavaScript. C

Jul 5, 2022
Cross-platform shared memory stream/buffer, header-only library for IPC in C/C++.
Cross-platform shared memory stream/buffer, header-only library for IPC in C/C++.

libsharedmemory libsharedmemory is a small C++11 header-only library for using shared memory on Windows, Linux and macOS. libsharedmemory makes it eas

Dec 4, 2022