How to free allocated slice partially?

test "example" {
    const buf = try std.heap.page_allocator.alloc(u8, 10);
    std.heap.page_allocator.free(buf[5..]);
}

This test panics with incorrect alignment error. I also tried rawFree with different alignments, but was getting the same error anyway.

Is it even possible to do this?

In the real code I allocate a huge slice, write some data there, store the filled part and cache the unused one for future usage if it exists. Partial deallocation raises the panic

Try checking .shrinkToLen of an ArrayList. Tldr, there is an .remap function on Allocator

remap requires pointer to the begging of the original allocation, but I need to deallocate the second part in the different context where the original slice is no longer available

This definitely won’t work. It looks like what you want is a custom memory pool (slot map).

Allocating, reallocating, and freeing strategies are a very complicated topic in computer. Different allocators have their own strategies. But the free() as a function will not do partially like that.

You may need to rethink about your memory allocating and freeing strategies, and you may also need memory pools or try other allocators.

Under the hood, even the ArrayList handles growing data by allocating a whole fixed size memory (2x of size than previous allocating IIRC), then copying the data to them. Removing will not free the memory. It’s shrinking that free the memory by allocating a smaller size and copying the data to it, then freeing the big one…

Frequently allocating and freeing a few slots may need a lot of syscalls which slows the computer down… People keep finding the balance between memory efficiency and speed.

This book is very good to understand how memory allocating work under the hood: 3  Memory and Allocators – Introduction to Zig

Andrew’s speech also discussed about the speed of syscalls comparing to many other operations: https://m.youtube.com/watch?v=IroPQ150F6c&t=387s&pp=2AGDA5ACAQ%3D%3D

Regardless you need to give it the start of the actual allocation, that is the semantics of the api, as it may be necessary depending on the implementation.

To shrink an allocation you would use the resize or remap functions.

test "resize" {
    // should work with both std.heap.page_allocator and some other allocators
    // const allocator = std.heap.page_allocator;
    const allocator = std.testing.allocator;
    const len = 1000000;
    // allocate a million bytes
    var buf = try allocator.alloc(u8, len);
    defer allocator.free(buf);
    const new_len = len / 2;
    // use first half million
    @memset(buf[0..new_len], '1');
    // free the remaining half million
    if (allocator.resize(buf, new_len)) {
        buf = buf[0..new_len];
    } else return error.ResizeFailed;
    // do something with buf that is now half million bytes
    try std.testing.expectEqual('1', buf[499999]);
}

Thanks for the answers!

It seems that in this imperfect world my big brain caching strategy is impossible due to hardware alignment constraints