【问题标题】:Should I bother cleaning array in node.js?我应该费心清理 node.js 中的数组吗?
【发布时间】:2016-01-28 02:08:46
【问题描述】:

在我的一个脚本中,我广泛使用数组来临时存储数据。我面临的问题是我有很多代码处理数组,所以我可以经济地利用空间。

既然 Node.js 数组是关联数组,我还要麻烦吗?

我目前的解决方案是:

//Get the minimum empty id in array
function get_id(callback) {
    var i = 0;
    while(array[i] != null) {
        i = i + 1;
    }
    array[i] = 0;
    callback(i);
}


get_id(function (i) {
    array[i] = {large object};
    //...
    array[i] = null;
});

但我觉得这是错误的并且容易出错。

我可以这样做吗:

array[i] = {large object};
i = i + 1;
//...
array[i] = null;

还是会导致大量内存消耗?

array 是使用它的模块的全局变量。

减少代码(我已经删除了所有未链接到数组 player.active_mission 的计算):

var player = {},
    missions = [{time: 1000}];

function end_mission(mission, squad, mission_log, callback) {
    //Make all the computing of the mission to know if the player won...
    callback(mission_log);
}

function get_ami(callback) {
    var i = 0;
    while(player.active_mission[i] != null) {
        i = i + 1;
    }
    player.active_mission[i] = 0;
    callback(i);
}

function wait_mission(mission, squad, mission_log, i, time, callback) {
    setTimeout(function () {
        console.log('End of mission');
        player.active_mission[i] = null;
        end_mission(mission, squad, mission_log, callback);
    }, time);
}

function start_mission(mission, squad, callback) {
    var mission_log = {mission: mission, time_start: new Date(), completed: false, read: false};

    //Verify if the player can start the mission...

    console.log('start_mission');
    get_ami(function (i) {
        player.active_mission[i] = {mission: mission, squad: squad, mission_log: mission_log}
        wait_mission(mission, squad, mission_log, i, missions[mission].time, callback);
    });
}

player.active_mission = [];

//This part is inside get request, after sanitizing all input
start_mission(0, [0, 1], function (r) {
    //r.id = req.session.player_id;
    if(r.error) {
        console.log('start: error: ' + r.error);
    } else {
        console.log('start: Success: ' + r.result);
    }
});

player.active_mission 保存玩家所有未完成的请求,如果玩家在完成前退出需要保存。我的问题是我应该尝试使用小 id 保留它,还是继续使用 .push() 并使用 .length() 获取 id?

简而言之:如果一个数组只有 null 用于第 1000 个第一个 id,并且仅在数组 [1000] 处开始有数据,我是否在浪费内存?

【问题讨论】:

  • 清洁是什么意思?
  • array 来自哪里(它在哪里声明,它的作用域和生命周期是什么)?为什么要把大对象放在数组里呢?
  • 请向我们展示您的完整代码。
  • @Bergi: 数组是模块中的全局变量,因为我必须能够转储所有当前请求,我发现最好将它们全部放在一个数组中,而不是尝试获取所有等待进程并转储它们。
  • “等待进程”是什么意思?你在这里做任何异步的事情吗?您的 get_id 示例看起来像您将对象放在函数开头的数组中,并在最后删除它。你真的在用它做什么?实际代码会有所帮助。

标签: javascript arrays node.js


【解决方案1】:

NodeJS 有一个垃圾收集器来销毁无法访问的对象/数组/变量。

所以当你执行array[i] = {large object}; 时,大对象会在内存中并且会一直留在这里。当您执行array[i] = null; 时,垃圾收集器将擦除大对象(当然只有在没有其他对该对象的引用时)。

所以是的,删除对无用对象的引用以让垃圾收集器清理它总是好的。

1000个null(或未定义)的数组对内存的影响不会很大。

如果你想保留你的记忆,你应该使用一个对象而不是一个数组。您可以使用以下语法:

var obj = {};
obj[id] = {large object};

// Free the id
delete obj[id];

【讨论】:

  • 您应该使用array.splice(i, 1); 而不是array[i] = null 这将保留数组中的键。
  • 在任何一种情况下,我都会删除大对象,但我需要保持 id 不变,因此将使用= null。我的问题是,我应该尽量保持 id 最小吗?如果数组在array[1000] 之前只有空值,我是不是在浪费内存?
  • @dev-null: 不,splice(除了速度慢)不适用于使用数组中的索引作为标识符的 OP。
  • It is always good to remove references 言过其实。 JS 是一种垃圾收集语言,因此通常使用清理来污染代码是错误的。只有在非常特殊的情况下才开始删除引用。
【解决方案2】:

我可以这样做吗:

i = i + 1;
array[i] = null;

还是会导致大量内存消耗?

是的,考虑到 array 是一个全局变量,并且不会自行被垃圾收集,不断地填充它 值(即使只有 null 值)最终会让你运行内存不足。

您的 get_id 方法回收未使用的 ID 确实有效,但性能极差 - 它需要线性时间才能找到新 ID。因此,它适用于并发任务很少的少数用户,但无法扩展。

您宁愿使用一个对象和其中的delete 键,这样就不会在计数时遇到问题:

var count = 0;
var missions = {};

function somethingThatNeedsTheStore() {
    var id = count++;
    missions[id] = …;
    // later
    delete missions[id];
}
// repeatedly call somethingThatNeedsTheStore()

或者实际上,在最近的节点版本上,您应该考虑改用 Map

var count = 0;
var missions = new Map;

function somethingThatNeedsTheStore() {
    var id = count++;
    missions.set(id, …);
    // later
    missions.delete(id);
}
// repeatedly call somethingThatNeedsTheStore()

【讨论】:

  • 我的印象是delete 本身性能不佳,因为它或多或少会在为对象分配的内存中造成一个空洞,从而导致碎片?
  • @JaredSmith:或多或少,在类似记录的对象中(想想struct)。然而,一段时间后,引擎会意识到您正在字典模式中使用该对象,并且这样做会更有效率。它最终会回收内存(如果不被其他键重用),这对您的情况至关重要。不是deleteing 该属性将不断增长您的对象,就像它会增长数组一样。
  • @Bergi:地图看起来很有趣,非常感谢 :)
  • @Bergi 在那种情况下,我认为有相当数量的 FUD 在野外传播关于delete。谢谢你的澄清。
猜你喜欢
  • 2010-11-18
  • 1970-01-01
  • 1970-01-01
  • 2012-05-10
  • 1970-01-01
  • 2010-09-15
  • 2011-02-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多