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

如何避免JavaScript/TypeScript大量对象分配时的内存碎片?

JS/TS 解决大量对象内存碎片问题的方案

在JS/TS中,直接创建大量独立对象确实会因为每个对象的额外内存开销(如隐藏类、内部指针)导致内存碎片化。可以通过以下几种方式模拟C++中连续内存块的分配逻辑:

1. 使用 TypedArray 拆分属性存储

将Cell的每个属性单独存储在对应的TypedArray中,利用TypedArray的连续内存特性避免碎片。这种方式相当于把对象的属性"列存",通过索引关联同一Cell的不同属性:

class CellStore {
    private indices: Uint32Array;
    private ms: Int32Array;
    private ns: Int32Array;
    private gs: Float32Array;
    private hs: Float32Array;
    private prevs: Int32Array; // 存储对应Cell的索引,-1表示null

    constructor(size: number) {
        this.indices = new Uint32Array(size);
        this.ms = new Int32Array(size);
        this.ns = new Int32Array(size);
        this.gs = new Float32Array(size);
        this.hs = new Float32Array(size);
        this.prevs = new Int32Array(size);

        // 初始化默认值
        for (let i = 0; i < size; i++) {
            this.indices[i] = 0;
            this.ms[i] = -1;
            this.ns[i] = -1;
            this.gs[i] = 0;
            this.hs[i] = 0;
            this.prevs[i] = -1;
        }
    }

    // 获取指定索引的Cell属性
    getCell(index: number) {
        return {
            index: this.indices[index],
            m: this.ms[index],
            n: this.ns[index],
            g: this.gs[index],
            h: this.hs[index],
            prev: this.prevs[index] === -1 ? null : this.prevs[index]
        };
    }

    // 修改指定索引的Cell属性
    setCell(index: number, props: Partial<{index: number, m: number, n: number, g: number, h: number, prev: number | null}>) {
        if (props.index !== undefined) this.indices[index] = props.index;
        if (props.m !== undefined) this.ms[index] = props.m;
        if (props.n !== undefined) this.ns[index] = props.n;
        if (props.g !== undefined) this.gs[index] = props.g;
        if (props.h !== undefined) this.hs[index] = props.h;
        if (props.prev !== undefined) this.prevs[index] = props.prev === null ? -1 : props.prev;
    }
}

// 使用示例
const cellStore = new CellStore(999999);
cellStore.setCell(0, {m: 5, n: 10});
const cell0 = cellStore.getCell(0);

2. 扁平化数组存储完整对象数据

将每个Cell的所有属性按顺序存入单个大数组,通过计算偏移量访问对应属性,同样利用数组的连续内存特性:

const CELL_PROP_COUNT = 6; // index, m, n, g, h, prev(索引,-1为null)
const size = 999999;
const cellData = new Float64Array(size * CELL_PROP_COUNT); // 用Float64兼容所有数值类型

// 初始化
for (let i = 0; i < size; i++) {
    const offset = i * CELL_PROP_COUNT;
    cellData[offset] = 0;       // index
    cellData[offset + 1] = -1;  // m
    cellData[offset + 2] = -1;  // n
    cellData[offset + 3] = 0;   // g
    cellData[offset + 4] = 0;   // h
    cellData[offset + 5] = -1;  // prev
}

// 访问第k个Cell的属性
const k = 100;
const offset = k * CELL_PROP_COUNT;
const cellK = {
    index: cellData[offset],
    m: cellData[offset + 1],
    n: cellData[offset + 2],
    g: cellData[offset + 3],
    h: cellData[offset + 4],
    prev: cellData[offset + 5] === -1 ? null : cellData[offset + 5]
};

// 修改属性
cellData[offset + 1] = 20; // 修改m值

3. 优化普通对象数组的内存开销(次优方案)

如果必须使用对象数组,可以通过减少对象的额外开销缓解碎片:

  • 使用Object.create(null)创建无原型的对象,避免原型链的内存开销
  • 确保所有对象结构一致,让JS引擎能优化为隐藏类(Hidden Class),减少内存开销
function createCell() {
    return Object.create(null, {
        index: { value: 0, writable: true },
        m: { value: -1, writable: true },
        n: { value: -1, writable: true },
        g: { value: 0, writable: true },
        h: { value: 0, writable: true },
        prev: { value: null, writable: true }
    });
}

const cellArray = new Array(999999);
for (let i = 0; i < cellArray.length; i++) {
    cellArray[i] = createCell();
}

说明

JS/TS中没有直接像C++那样分配连续的对象数组的语法,但TypedArray是底层连续内存的实现,能最大程度减少内存碎片,同时降低每个元素的额外内存开销。前两种方案本质是用"结构化的连续内存"模拟对象数组,适合对内存敏感的场景。

内容的提问来源于stack exchange,提问作者刘不思

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 14:06:18