Node.js - Segfault:11使用相当大的数组

时间:2017-09-04 22:42:35

标签: javascript arrays node.js segmentation-fault

这里的第二篇帖子真的让我摸不着头脑。我有一个处理数组的函数,试图找到类似的数据。该数组包含1410个元素,我认为这些元素很多,但Node或我的电脑无法处理这些元素。

我的代码给出了“Segmentation Fault:11”错误,我发现这与内存访问问题有关,所以我甚至想要测试我的Mac内存,但一切都很好。段错误使调试非常困难,这就是我来这里的原因。

出现问题的代码就在这里:

return matchings.map(matchArray => {
  const namesList = matchArray
    .map(matchItem => matchItem.name)
    .sort((a, b) => a.localeCompare(b))

  const symbolsList = matchArray
    .map(matchItem => matchItem.symbol)
    .sort((a, b) => a.localeCompare(b))

  return {
    name: common.getMode(namesList),
    symbol: common.getMode(symbolsList),
    matches: matchArray
  }
}).sort((a, b) => a.name.localeCompare(b.name))

matchings是我正在谈论的数组。 common.getMode(array)有以下代码:

array.sort()

const stats = {
  top: {
    name: '',
    freq: 0
  },
  current: {
    name: array[0],
    freq: 1
  }
}

for (let idxName = 1; idxName < array.length; idxName++) {
  const currentName = array[idxName]
  const lastName = array[idxName - 1]

  if (currentName === lastName) {
    stats.current.freq++
  } else {
    if (stats.current.freq > stats.top.freq) {
      stats.top.name = stats.current.name
      stats.top.freq = stats.current.freq
    }
    stats.current = {
      name: currentName,
      freq: 1
    }
  }
}

if (stats.current.freq > stats.top.freq) {
  stats.top.name = stats.current.name
  stats.top.freq = stats.current.freq
}

return stats.top.name

值得一提的是,当使用较小的~1000的数组执行时,代码工作正常,这让我相信它不是我的代码。关于Node的Segfault 11的在线内容也很少,但没有帮助。

任何想法都非常感谢!

1 个答案:

答案 0 :(得分:1)

TL; DR 使用tail call optimization消除call stack的压力。

修改(附说明)

请参阅Understanding Javascript Functions Execution...,了解call stackmemory heapqueue之间的区别。对象和变量位于heap之内,而call stack中引用了函数调用,第二个数据集已耗尽(16'000个堆栈帧);所以你的算法无法跟上,因为它无法继续分配新的函数调用。

请参阅this StackOverflow answer,其中指出了有关call stackthis one too的更多信息,其中指出了获取heap数据的方法。

原始回答

我可能完全没有了,但我很想知道将你的循环转换为递归是否有助于记忆应对。我会在我的盒子上尝试它,但设置一切都很麻烦。

你可以尝试一下吗?它使用扩展运算符和数组解构,因此您可能必须将 babel-preset-stage-0 添加到项目中,并添加.babelrc文件。

<强>的Javascript

let common = {};
common.getMode = (arr, compare_fn) => {
  const compare = !!compare_fn ? compare_fn : (a, b) => a.localeCompare(b)
  arr.sort(compare)

  const stats = {
    top: {
      name: '',
      freq: 0
    },
    current: {
      name: arr[0],
      freq: 1
    }
  }

  for (let i=1, imax = arr.length ; i < imax ; ++i) {
    const currentName = arr[i]
    const lastName = arr[i - 1]

    if (currentName === lastName) {
      stats.current.freq++
    } else {
      if (stats.current.freq > stats.top.freq) {
        stats.top.name = stats.current.name
        stats.top.freq = stats.current.freq
      }
      stats.current = {
        name: currentName,
        freq: 1
      }
    }
  }

  if (stats.current.freq > stats.top.freq) {
    stats.top.name = stats.current.name
    stats.top.freq = stats.current.freq
  }

  return stats.top.name
};

const build_prop_list = (prop, input_array, output_array = []) => {
  if(input_array.length == 0) return output_array;
  else {
    const [current, ...tail] = input_array;
    const new_array = [...output_array, current[prop]];
    return build_prop_list(prop, tail, new_array);
  }
}

const work = (input_array, output_array = []) => {
  if(input_array.length == 0) return output_array.sort((a, b) => a.name.localeCompare(b.name));
  else {
    const [matchArray, ...tail] = input_array;

    const namesList = build_prop_list("name", matchArray);
    const symbolsList = build_prop_list("symbol", matchArray);

    const new_element = {
      name: common.getMode(namesList),
      symbol: common.getMode(symbolsList),
      matches: matchArray
    };

    const new_array = [...output_array, new_element];
    return work(tail, new_array);
  }
}

let result = work(insert_your_json_here);

修改

您还可以将尾部呼叫优化应用于for中的common.getMode(...)循环。第一次迭代的行为是不同的,因为lastName不引用数组的最后一个名称(索引:-1),而是第一个。看看它是否符合您的需求,您可以更优化您的代码 这应该取代for中的common.getMode(...)循环。

  const feed = (input_array) => {
    if(input_array.length == 0) return;
    const [lastName, currentName, ...tail] = input_array;

    if (currentName === lastName) {
      stats.current.freq++
    } else {
      if (stats.current.freq > stats.top.freq) {
        stats.top.name = stats.current.name
        stats.top.freq = stats.current.freq
      }
      stats.current = {
        name: currentName,
        freq: 1
      }
    }

    return feed(tail);
  }(arr);