为啥这段代码会造成内存泄露啊?

查看 140|回复 14
作者:lp4298707   
function handleData() {
  list = data.value;
  const now = new Date().getTime()
  list.forEach(item => {
    const isTop = item.remindEndTime > now
    item.shine = isTop;
    item.sort = isTop ? 0 : 1;
  })
  // 闪烁的放最前 再以更新时间排序
  list = orderBy(list, ['sort', 'updateTime'], ['asc', 'desc'])
  visibleData.value = list
  list = null
}
onMounted(() => {
  flightClient.subscribe(WS_PREFIX + '/xxx/xxx', res => {
    data.value = res
    handleData()
  })
  timer = setInterval(() => {
    handleData()
  }, 300)
})
onBeforeUnmount(() => {
  clearInterval(timer)
})
每次调用我都把 list 置为空了 为什么还是会导致内存蹭蹭涨?
如果把
list = orderBy(list, ['sort', 'updateTime'], ['asc', 'desc'])
这段代码去掉 就没问题了
morenacl   
两个 list 不是同一个 list
NessajCN   
orderBy 定义呢?
williamcc   
这段代码存在潜在的内存泄漏风险,主要原因是 setInterval 和数据处理方式的结合导致的。以下是详细分析:
潜在的内存泄漏原因:
setInterval 和闭包:
setInterval 函数会创建一个新的计时器,每 300 毫秒重复调用 handleData() 函数。
每次调用 handleData() 都会创建一个闭包,闭包会捕获周围作用域中的变量引用,包括 data.value 、list 和 visibleData.value 。
数据累积:
当新的数据通过 websocket 订阅到达时,data.value 会更新,并调用 handleData() 函数。
在 handleData() 内部,会创建一个新的数组 list ,并将 data.value 的值赋给它。
然后对 list 进行排序,并将其赋值给 visibleData.value 。
然而,原始的 list 数组,它仍然持有对旧 data.value 的引用,并没有被显式清除或垃圾回收。
闭包引用:
每个由 setInterval 创建的闭包都保留了对旧 list 数组的引用,即使它不再需要了。
这就阻止了旧的 data.value 被垃圾回收,随着时间的推移导致内存累积。
解决方案:
在卸载时清除计时器:
确保在 onBeforeUnmount 中正确调用 clearInterval(timer) 来停止计时器,并防止进一步创建闭包。
避免不必要的数组创建:
不要在每次 handleData() 调用中创建新的 list 数组,可以考虑直接对 data.value 数组进行排序,或使用更高效的排序算法。
使用弱引用 (高级):
如果需要在闭包中维护引用而不导致内存泄漏,可以考虑使用 WeakMap 或 WeakSet 数据结构。这些结构持有弱引用,不会阻止垃圾回收。
注意: 使用弱引用需要仔细考虑对象生命周期和垃圾回收行为。
其他注意事项:
内存分析: 使用浏览器开发者工具或内存分析工具来跟踪内存使用情况并识别泄漏。
数据大小: 如果 data.value 数组包含大量数据,内存影响会更显著。考虑高效处理大型数据集的策略。
改进示例 (避免创建数组):
function handleData() {
const now = new Date().getTime();
data.value.forEach(item => {
const isTop = item.remindEndTime > now;
item.shine = isTop;
item.sort = isTop ? 0 : 1;
});
// 直接对 data.value 进行排序
data.value = orderBy(data.value, ['sort', 'updateTime'], ['asc', 'desc']);
visibleData.value = data.value;
}
yrk20212021   
import { onMounted, onBeforeUnmount } from 'vue'
// Assuming flightClient and WS_PREFIX are defined somewhere else
let timer = null;
function handleData() {
const now = new Date().getTime();
const newData = data.value.map(item => {
const isTop = item.remindEndTime > now;
return {
...item,
shine: isTop,
sort: isTop ? 0 : 1
};
});
// Sort only if there are changes in shine or updateTime
newData.sort((a, b) => {
if (a.shine !== b.shine) {
return a.shine ? -1 : 1;
}
return b.updateTime - a.updateTime;
});
visibleData.value = newData;
}
onMounted(() => {
const subscription = flightClient.subscribe(WS_PREFIX + '/xxx/xxx', res => {
data.value = res;
handleData();
});
timer = setInterval(handleData, 300);
});
onBeforeUnmount(() => {
clearInterval(timer);
// Unsubscribe from WebSocket to prevent memory leaks
flightClient.unsubscribe(subscription);
});
ProxyXAI   
这可能是因为你的 `orderBy` 函数在排序时创建了新的数组,而原有的 `list` 数组并没有被垃圾回收。这可能是因为 `visibleData.value` 仍然引用着这个数组,或者其他地方也有对这个数组的引用。
你可以尝试在 `orderBy` 之后,手动将 `list` 设置为 `null`,或者使用 `list.length = 0` 清空数组,再设置 `visibleData.value = orderBy(...)`,这样可以确保 `list` 数组被垃圾回收。
另外,你的 `handleData` 函数并没有声明 `list` 为局部变量,这可能导致它成为全局变量,这也可能是内存泄露的原因。你应该使用 `let` 或 `const` 关键字声明 `list`。
示例代码:
```javascript
function handleData() {
let list = data.value;
const now = new Date().getTime()
list.forEach(item => {
const isTop = item.remindEndTime > now
item.shine = isTop;
item.sort = isTop ? 0 : 1;
})
// 闪烁的放最前 再以更新时间排序
visibleData.value = orderBy(list, ['sort', 'updateTime'], ['asc', 'desc'])
list.length = 0
list = null
}
```
记住,JavaScript 的垃圾回收是基于引用的。只要一个对象没有被引用,它就会被垃圾回收。但如果你的代码中有对这个对象的引用,那么它就不会被回收,即使你手动设置为 `null`。
yxd19   
v2ex 允许 ai 回复了?
/about#:~:text=%E2%80%A2%20%E8%AF%B7%E4%B8%8D%E8%A6%81%E6%8A%8A%20AI%20%E7%94%9F%E6%88%90%E7%9A%84%E5%86%85%E5%AE%B9%E5%8F%91%E9%80%81%E5%88%B0%E8%BF%99%E9%87%8C
flyqie   
@yxd19 #6
建议 @livid ,貌似还是不允许,只是不反馈就不查,要是 ai 生成后自己审阅过的貌似是允许的(因为这其实跟自己发区别不大了)。
lp4298707
OP
  
@NessajCN orderBy 就是 lodash 的 orderBy
wunonglin   
@Livid 这里都是 AI 回复鸭,麻了。
您需要登录后才可以回帖 登录 | 立即注册

返回顶部