这里的第二篇帖子真的让我摸不着头脑。我有一个处理数组的函数,试图找到类似的数据。该数组包含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的在线内容也很少,但没有帮助。
任何想法都非常感谢!
答案 0 :(得分:1)
TL; DR 使用tail call optimization
消除call stack
的压力。
修改(附说明)
请参阅Understanding Javascript Functions Execution...,了解call stack
,memory heap
和queue
之间的区别。对象和变量位于heap
之内,而call stack
中引用了函数调用,第二个数据集已耗尽(16'000个堆栈帧);所以你的算法无法跟上,因为它无法继续分配新的函数调用。
请参阅this StackOverflow answer,其中指出了有关call stack
和this 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);