Overview

Pool arrays are temporary — valid only within their @with_pool scope. When the scope ends, the memory is marked for reuse.

@with_pool pool begin
    v = acquire!(pool, Float64, 100)
    sum(v)       # ✅ return computed values
    copy(v)      # ✅ return owned copies
end
# v is now invalid — its memory may be reused by the next acquire!
@with_pool pool function bad()
    v = acquire!(pool, Float64, 100)
    return v     # ❌ v escapes the pool scope
end

You don't have to catch these yourself. AdaptiveArrayPools provides a two-layer safety net:

LayerWhat It CatchesCost
Compile-timeObvious escapes, structural mutationsZero (macro analysis)
Runtime (RUNTIME_CHECK = 1)Everything else: opaque escapes, hidden mutations~5ns/slot, off by default

Compile-time analysis is always active. Runtime safety is opt-in for development and fully eliminated in production — zero overhead.

Quick Reference

acquire! vs acquire_view!

FunctionReturnsBest For
acquire!Native Array{T,N} (or BitArray{N} for Bit)General use, BLAS/LAPACK, FFI
acquire_view!View types (SubArray, ReshapedArray)When views are preferred

Both follow the same scope rules. Use acquire! by default.

Thread Safety

Pools are task-local — each thread automatically gets its own pool:

# ✅ Safe: each task has independent pool
Threads.@threads for i in 1:N
    @with_pool pool begin
        a = acquire!(pool, Float64, 100)
    end
end

# ❌ Unsafe: pool created outside threaded region
@with_pool pool begin
    Threads.@threads for i in 1:N
        a = acquire!(pool, Float64, 100)  # race condition!
    end
end

See Multi-Threading for more patterns.