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

Overview

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
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

    opened by briansoe66 23
  • 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
    
    opened by matt-cross 13
  • 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

    opened by kevin-- 13
  • 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

    opened by nick-thompson 12
  • 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})
    
    opened by wtsnyder 12
  • 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?

    opened by gabyx 12
  • 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

    opened by jwdevel 11
  • [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

    more-info-needed 
    opened by Baren123 10
  • 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 =)

    opened by gabyx 10
  • 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?

    opened by jwdevel 9
  • 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)
    
    more-info-needed 
    opened by rushipatel 9
  • [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.

    opened by oberrich 3
  • `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.

    opened by psalz 1
  • 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?

    opened by burnpanck 1
  • 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.

    opened by Manu343726 3
Releases(v0.7-2)
  • v0.7-2(Aug 1, 2022)

    Deprecate virtual_memory_page_size; use get_virtual_memory_page_size() instead. (#132)

    CMake improvements:

    • Generate container node sizes using CMake, which makes cross-compiling easier (#129)
    • Set CMAKE_RUNTIME_OUTPUT_DIRECTORY properly to support shared libraries (#132)
    Source code(tar.gz)
    Source code(zip)
  • v0.7-1(Sep 5, 2021)

    Just bugfixes:

    • CMake: automatically link libatomic on platforms where that is necessary (#95)
    • catch small block sizes of memory_pool (#113)
    • fix buffer overflow in memory_pool_collection's array allocation (#99)
    • fix compatibility with Windows UWP (#102)
    • fix computation of memory_pool::min_block_size (#110)
    • fix debug assertion in free lists (#111)
    Source code(tar.gz)
    Source code(zip)
  • v0.7(Dec 2, 2020)

    BREAKING: Removed the use of the compatibility library to automatically generate macros and workaround for older compilers. The important compatibility workarounds like the __builtin_clz extension are still used, but workarounds for missing C++11 library features have been removed. In particular, the library now requires compiler support for noexcept, constexpr, alignof and thread_local.This means that GCC 4.8 and Visual Studio version 12.0 (both released in 2013), are no longer supported.

    Adapter

    BREAKING: Remove Mutex support from allocator_reference and consequently from std_allocator, allocator_deleter, etc. Embedding the Mutex with the reference was fundamentally broken and unusable to ensure thread safety. Use a reference to a thread_safe_allocator instead, which actually guarantees thread safety.

    Allocator

    Add ability to query the minimal block size required by a memory_pool or memory_stack that should contain the given memory. Due to internal data structures and debug fences this is more than the naive memory request, so it can be computed now.

    Bugfixes

    • more CMake improvements for cross-compiling, among others
    • bugfixes to support UWP (#80), VxWorks (#81) and QNX (#85, #88, among others)
    • better support missing container node size (#59, #72, among others)
    • fix alignment issues in debug mode
    • fix tracking for allocators without block allocators
    Source code(tar.gz)
    Source code(zip)
  • v0.6-2(Oct 2, 2019)

    Various bug fixes, compiler warning workarounds and CMake improvements accumulated over past two years. Most notable changes:

    • cross compilation works now
    • fallback_allocator is default constructible if stateless
    • add unique_base_ptr to support a unique ptr to a base class
    • add allocate_unique overloads that take a custom mutex
    • allocator deleters are default constructible
    Source code(tar.gz)
    Source code(zip)
  • v0.6-1(Oct 31, 2017)

    • fix CMake configuration error
    • fix double free error in segregator
    • add static_assert() when default constructing a stateful std_allocator
    • fix various compiler warnings
    Source code(tar.gz)
    Source code(zip)
  • v0.6(Nov 21, 2016)

    See also: https://foonathan.github.io/blog/2016/11/21/memory-0.6.html

    Tool

    • better MSVC support
    • improved compilation time

    Core

    • add literal operators for memory sizes (4_KiB)
    • more flexible make_block_allocator
    • composable allocator concept

    Allocator

    • improved temporary_allocator: explicit separation into temporary_stack, improved automatic creation
    • new memory_stack_raii_unwind for automatic unwinding
    • new iteration_allocator
    • make allocators composable
    • add facilities for joint memory allocations

    Adapter

    • add shared_ptr_node_size
    • add string container typedef
    • add fallback_allocator
    • add segregator

    Bugfixes

    • OSX support
    • various warnings fixed
    Source code(tar.gz)
    Source code(zip)
  • v0.5-3(Apr 17, 2016)

    Fixes a few minor bugs in memory_stack also the next_capacity() functions so that they return the exact results.

    Array allocations in memory_pool_collection are improved and now supported for pool types that do not support them natively (small_node_pool) also add _left() to pool_capacity() and capacity() like in the other arenas.

    Source code(tar.gz)
    Source code(zip)
  • v0.5-2(Apr 13, 2016)

    Fixes a crash in memory_pool<array_pool> that sometimes happens for array allocations. Also fixes a non-critical performance bug in memory_pool<small_pool> and a typo in Readme.

    Source code(tar.gz)
    Source code(zip)
  • v0.5-1(Mar 18, 2016)

  • v0.5(Feb 23, 2016)

    • improved CMake build system, now supports cmake installation and find_package()
    • improved low-level allocators and added malloc_allocator
    • add virtual memory interface and allocators
    • add allocators using a fixed-sized storage block
    • introduced BlockAllocator concept and various implementations
    • new class template memory_arena that is used inside the higher level allocators, allows more control over the internal allocations
    • add wrappers/adapters for the polymorphic memory resource TS
    • improved tracking classes
    • other improvements like concept checks and more exception classes
    • internal changes

    See also: http://foonathan.github.io/blog/2016/02/23/memory-0.5.html

    Source code(tar.gz)
    Source code(zip)
  • v0.4-2(Dec 21, 2015)

  • v0.4-1(Nov 1, 2015)

  • v0.4(Sep 12, 2015)

    • polished up the interface, many breaking changes in the form of renaming and new header files
    • added unified error handling facilities and handler functions in case exceptions are not supported
    • improved old allocator adapters by introducing allocator_storage template
    • improved allocator_traits making them more powerful and able to handle Allcoator types directly
    • added type-erased allocator storage
    • added node-size debugger that obtains information about the container node sizes
    • most parts now work on a freestanding implementation
    • used foonathan/compatibility for CMake compatibility checks
    • added miscellaneous tiny features all over the place
    • many internal changes and bugfixes
    Source code(tar.gz)
    Source code(zip)
  • v0.3(Jun 13, 2015)

    • added debugging options such as memory filling and deallocation and leak check
    • improved performance of pool allocators
    • changed complete project structure and CMake
    • many internal changes and bugfixes and automated testing
    Source code(tar.gz)
    Source code(zip)
  • v0.2(May 9, 2015)

    • added temporary_allocator as portable alloca
    • added small_node_pool type optimized for low-overhead small object allocations
    • added various allocator adapters including a thread_safe_allocator for locking
    • better compiler support
    • many internal changes and bugfixes
    Source code(tar.gz)
    Source code(zip)
  • v0.1-1(Mar 30, 2015)

  • v0.1(Mar 29, 2015)

Owner
Jonathan Müller
Interested in C++, I write libraries and blog about them.
Jonathan Müller
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.

A.P. Jo. 4 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

Emery Berger 927 Jan 2, 2023
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

PLASMA @ UMass 1.5k 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

null 1 Feb 28, 2022
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

Mattias Jansson 1.7k 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

null 11 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

Sam 47 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

Hypervisor 8 Dec 7, 2022
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

Mariano Trebino 1.4k 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

Alexander Nestorov 31 Nov 9, 2022
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

Microsoft 7.6k 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.

GrapheneOS 893 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

Microsoft 1.1k 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

null 9 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

Dwight Hohnstein 68 Dec 2, 2022
Fast C++ IPC using shared memory

Fast C++ IPC using shared memory

Dheeraj R Reddy 397 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

Unsal Ozturk 2 Feb 4, 2022
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

cristei 4 Jul 5, 2022
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

Aron Homberg 10 Dec 4, 2022