Skip to content

Releases: pboyd/malloc

v1.2.1

25 Feb 02:01

Choose a tag to compare

VirtBackend: Addr and Release (breaking change)

VirtBackend now returns *VirtReservationBackend instead of ArenaBackend, exposing two new methods to callers.

Addr() returns the base address of the reserved region. Use it to verify alignment or placement requirements before committing to the arena:

backend, err := malloc.VirtBackend(64 << 20)
if err != nil {
    log.Fatal(err)
}

if backend.Addr() % alignment != 0 {
    backend.Release()
    log.Fatal("unsuitable address")
}

arena := malloc.NewArena(malloc.Backend(backend))

Release() frees the entire reservation. Call it when the address returned by Addr is unsuitable, or to free the backend's memory independently of the arena.

Migration

If you stored the result of VirtBackend as an ArenaBackend interface, update the declaration to the concrete type:

// Before
var backend malloc.ArenaBackend
backend, err = malloc.VirtBackend(size)

// After
backend, err := malloc.VirtBackend(size)

v1.2.0

20 Feb 13:29

Choose a tag to compare

VirtBackend

v1.2.0 adds VirtBackend, a fixed-capacity backend that reserves a contiguous virtual address range at startup and commits physical memory on demand.

backend, err := malloc.VirtBackend(64 << 20) // reserve 64 MiB
if err != nil {
    log.Fatal(err)
}

Each Grow call extends the committed region in place, so all allocations share the same base address. This makes VirtBackend a good fit for arenas where you know the maximum size upfront and need pointers to remain valid after the arena grows. When committed memory reaches the reserved capacity, Grow returns ErrOutOfMemory.

On Unix, VirtBackend reserves address space with PROT_NONE and commits pages via mprotect. On Windows, it uses MEM_RESERVE followed by MEM_COMMIT. VirtBackend implements ProtectedArenaBackend.

MmapBackend options (breaking change)

MmapBackend now accepts variadic BackendOpt options instead of positional prot and flags integers.

Before:

backend := malloc.MmapBackend(syscall.PROT_EXEC, 0)

After:

backend := malloc.MmapBackend(malloc.MmapProt(syscall.PROT_EXEC))

A new MmapAddr option requests a preferred mapping address from the kernel. These same options work with VirtBackend.

Bug fixes

  • Fixed exec protection flag for MmapBackend on Windows.

v1.1.0

15 Feb 18:55

Choose a tag to compare

Memory Protection Control

This release adds memory protection control through the ProtectedArenaBackend interface. Use MmapBackend.Protect() to change page permissions on memory-mapped allocations.

The protection value passes directly to the underlying system call (mprotect on Unix, VirtualProtect on Windows), giving you full control over page permissions.

BSD Support

Builds now succeed on FreeBSD, OpenBSD, and NetBSD. Cross-compilation tests verify compatibility with these platforms.


What's Changed

  • feat: add option to change protections on mmap pages by @pboyd in 919d615
  • fix: Verify that compilation works for a few BSD variants by @pboyd in 401116a

Full Changelog: v1.0.0...v1.1.0

v1.0.0

14 Feb 21:29

Choose a tag to compare

Release Notes: v1.0.0

malloc v1.0.0 marks the first stable release version. The package now supports concurrent access, dynamic memory growth, and memory-mapped allocation.

Breaking Changes

Function signatures changed:

// Old (v0.10.0)
func NewArena(size uint64) *Arena
func NewArenaAt[T any](buf []T) *Arena

// New (v1.0.0)
func NewArena(size uint64, opts ...Opt) *Arena
func NewArenaAt[T any](buf []T, opts ...Opt) *Arena

Existing code continues to work without changes. The new optional parameters add configuration without breaking compatibility.

New Features

Thread-Safe Arenas

Arenas now protect concurrent access with a mutex. Multiple goroutines can allocate and free memory simultaneously.

arena := malloc.NewArena(64 * 1024)

// Safe to call from multiple goroutines
go func() {
    p, _ := malloc.Malloc[int](arena)
    malloc.Free(arena, p)
}()

Dynamic Growth

Arenas grow automatically when they run out of space. The backend determines how growth occurs.

// Starts small, grows as needed
arena := malloc.NewArena(1024, malloc.Backend(malloc.SliceBackend))

Memory-Mapped Allocation

The MmapBackend allocates memory through mmap(2) on Unix or VirtualAlloc on Windows. This keeps allocated memory outside the Go heap.

// Allocate 4KB via mmap
arena := malloc.NewArena(4096, malloc.Backend(malloc.MmapBackend(0, 0)))

Platforms: Linux, macOS, Windows

Improvements

  • Improved error detection for double-free bugs
  • Added GitHub Actions CI across Go 1.25, 1.26 and all supported platforms

Known Limitations

  • The mmap backend does not support BSD systems (except Darwin)
  • Growth performance depends on the backend implementation
  • Minimum allocation size remains 16 bytes

Migration Guide

From v0.10.0

No code changes required. The API remains compatible.

To opt into new features:

// Enable growth
arena := malloc.NewArena(1024, malloc.Backend(malloc.SliceBackend))

// Use mmap
arena := malloc.NewArena(4096, malloc.Backend(malloc.MmapBackend(0, 0)))

Requirements

  • Go 1.25 or later
  • For mmap support: Linux, macOS, or Windows

v0.10.0

31 Jan 20:16

Choose a tag to compare

Full Changelog: v0.9.0...v0.10.0