You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在连续内存块中构建元素可变的链表用于内存池实现?

完全可以实现,有两种常用的实现方案,都能满足「元素连续存储+可变操作+空闲链表管理」的需求:

方案1:原生无依赖实现(推荐入门使用)

核心思路是用不可变struct保证连续存储,通过封装索引句柄和操作方法屏蔽不可变特性,对外提供可变操作能力:

# 不可变Chunk,保证Vector存储时是连续内存布局
struct Chunk{T}
    next::Int
    data::T
end

# Pool结构体,封装底层存储和空闲链表头指针
struct Pool{T}
    chunks::Vector{Chunk{T}}
    free_head::Ref{Int} # 用Ref存储可变的空闲链表头
end

# 初始化指定类型和大小的内存池
function Pool(T, size::Int)
    size < 1 && error("Pool size must be at least 1")
    chunks = Vector{Chunk{T}}(undef, size)
    # 初始化链表指针,每个chunk的next指向下一个索引
    for i in 1:size-1
        chunks[i] = Chunk(i+1, zero(T))
    end
    # 最后一个chunk的next指向第一个,形成循环链表
    chunks[end] = Chunk(1, zero(T))
    return Pool(chunks, Ref(1))
end

# 分配空闲chunk,返回索引作为操作句柄
function allocate!(pool::Pool{T}) where T
    head = pool.free_head[]
    # 可自行添加内存耗尽的判断逻辑
    pool.free_head[] = pool.chunks[head].next
    return head
end

# 释放指定句柄的chunk,插回空闲链表头部
function deallocate!(pool::Pool{T}, handle::Int) where T
    old_head = pool.free_head[]
    # 仅修改next指针,保留原有data不重置(可根据需求添加重置逻辑)
    pool.chunks[handle] = Chunk(old_head, pool.chunks[handle].data)
    pool.free_head[] = handle
    return nothing
end

# 读取chunk存储的数据
get_data(pool::Pool{T}, handle::Int) where T = pool.chunks[handle].data

# 修改chunk存储的数据
function set_data!(pool::Pool{T}, handle::Int, new_data::T) where T
    old_chunk = pool.chunks[handle]
    pool.chunks[handle] = Chunk(old_chunk.next, new_data)
    return nothing
end

该方案的优势:

  • 所有Chunk都存储在Vector的连续内存块中,无额外堆分配,cache友好,符合实时场景需求
  • 对外仅暴露索引作为句柄,不会出现元素逃逸到数组外的情况
  • 封装接口完全屏蔽了Chunk不可变的特性,使用体验和可变元素完全一致

方案2:基于StructArrays的高性能实现

如果需要更高的字段修改性能,避免每次修改都重新构造Chunk实例,可以将Chunk的字段拆分为独立的连续数组,修改时直接操作对应数组的单个元素即可:

using StructArrays

struct Pool{T}
    next::Vector{Int} # 存储所有chunk的next指针,连续内存
    data::Vector{T} # 存储所有chunk的数据,连续内存
    free_head::Ref{Int}
end

function Pool(T, size::Int)
    size < 1 && error("Pool size must be at least 1")
    next = collect(2:size+1)
    next[end] = 1 # 形成循环链表
    data = fill(zero(T), size)
    return Pool(next, data, Ref(1))
end

function allocate!(pool::Pool{T}) where T
    head = pool.free_head[]
    pool.free_head[] = pool.next[head]
    return head
end

function deallocate!(pool::Pool{T}, handle::Int) where T
    old_head = pool.free_head[]
    pool.next[handle] = old_head
    pool.free_head[] = handle
    return nothing
end

get_data(pool::Pool{T}, handle::Int) where T = pool.data[handle]
set_data!(pool::Pool{T}, handle::Int, new_data::T) where T = (pool.data[handle] = new_data)

该方案的优势:

  • 两个数组均为连续内存,整体内存布局和连续存储Chunk完全一致
  • 修改next指针或data时无需构造新的结构体实例,性能更高,实现逻辑更简洁

内容的提问来源于stack exchange,提问作者BatWannaBe

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 17:06:00