![个人头像照片](https://ucc.alicdn.com/avatar/avatar3.jpg)
暂无个人介绍
2024年05月
node-memwatch 提供的堆内存差异信息包含了前后两次内存快照中各个对象的数量、大小以及变化情况。通过分析这些信息,可以找出哪些对象的数量或大小在持续增长,从而定位到具体的内存泄漏对象。例如,在上面的例子中,可以看到 LeakingClass 的数量在显著增加,说明可能是这个类造成了内存泄漏。
node-memwatch 的 leak 事件触发条件是连续 5 次 GC 后内存都是增长的。当这个条件满足时,node-memwatch 会认为存在内存泄漏,并触发 leak 事件,同时提供前后内存快照的差异信息。
除了使用 v8.getHeapStatistics 接口,还可以使用 node-memwatch 这样的 npm 包来监控内存泄漏问题。node-memwatch 可以监听 GC 事件和内存泄漏事件,并在发现内存泄漏时提供详细的堆内存差异信息,帮助定位具体的内存泄漏对象。
使用 v8.getHeapStatistics 接口可以获取 v8 堆内存的各种统计信息,如总堆大小、已用堆大小等。通过定期调用该接口并上报数据,可以实时监控 v8 堆内存的使用趋势,从而发现内存泄漏的迹象。
发布后监控线上 v8 堆内存泄漏问题,可以通过定期采集 v8 的堆内存数据,使用 v8.getHeapStatistics 接口每隔一段时间(如1分钟)上报到监控平台,实时统计 v8 堆内存使用趋势,以发现潜在的内存泄漏问题。
Chrome DevTools 的 Memory 和 Performance 工具在分析内存泄漏问题中起到了关键作用。Memory 工具可以从内存中对象的角度分析内存泄漏,通过比较不同时间点的内存快照来定位问题。而 Performance 工具则可以从代码执行的角度分析内存泄漏,通过录制和分析代码执行过程中的内存分配情况来定位导致内存泄漏的具体代码。这两个工具的结合使用,可以更有效地发现和解决内存泄漏问题。
"为了解决内存泄漏问题,可以对日志上报功能进行改进。在 onError 事件处理函数中,添加条件判断,过滤掉特定的错误信息(如 FetchError),避免递归触发 onError 事件。这样不仅可以解决内存泄漏问题,还可以减少不必要的错误日志上报。具体实现方式是在 onError 事件处理函数中添加条件判断,只有当错误信息不包含特定字符串时才进行日志上报。
javascript
import TraceSdk from '@ali/trace-sdk-node'
import log from 'electron-log'
// arms 实时日志上报平台
let trace = TraceSdk()
const sendErrorLog = trace.logError
log.catchErrors({
onError(error) {
// 过滤 arms fetch error 错误日志
if (!error?.message.includes('https://s-gm.mmstat.com/arms')) {
sendErrorLog(error)
}
},
})"
在排查内存泄漏问题时,发现电子应用的日志上报功能在网络请求失败时会递归触发 onError 事件,导致大量错误信息被持有,从而占用大量内存。特别是当请求到 https://s-gm.mmstat.com/arms 的地址失败时,会不断产生 FetchError,这些错误信息中包含的字符串和数组对象不断增长,最终导致了内存泄漏。
电子应用出现内存泄漏的原因可能是多种多样的,但通常与 JavaScript 代码中的引用问题有关。当对象不再需要时,如果它们仍然被其他对象引用,垃圾回收器就无法回收它们所占用的内存,从而导致内存泄漏。
在 Performance 面板中,点击内存分配情况的某个点,可以定位到导致内存分配的代码任务。进一步点击该任务代码,可以定位到具体的内存分配代码。通过分析这些代码,可以确定导致内存泄漏的根本原因。
首先,打开 Chrome DevTools 并选择 Performance 面板。点击面板下的垃圾回收按钮,手动触发一次 GC。然后勾选 Memory 选项,并点击录制按钮开始录制。等待一段时间后停止录制,并查看内存部分,特别是 JS Heap 的增长趋势。如果发现内存持续增长,则可能存在内存泄漏。
"在使用Memory工具定位内存泄漏问题时,需要注意以下几点:
确保在录制快照之前手动触发垃圾回收;
在比较快照时,注意分析哪些对象被添加或删除以及内存增长的主要来源;
最后,通过代码审查和分析来确认潜在的内存泄漏源。"
如果发现内存增长的主要原因是string对象,下一步应该是通过代码审查和分析来确定哪些代码逻辑导致了频繁使用string对象。这可能需要查看代码中的字符串操作、全局变量、闭包等,以找出潜在的内存泄漏源。
首先,打开Chrome DevTools并选择Memory面板。然后,点击“Collect garbage”按钮手动触发垃圾回收。接着,录制一次内存快照,并在一段时间后再次录制一次。通过比较这两次快照,可以分析内存增长情况并定位可能的内存泄漏。
内存泄漏的主要原因是进程不再需要的内存数据仍然被其他对象引用着。在JavaScript中,这通常是因为某些对象或变量被错误地保留或作用域链的某些部分没有被正确清理。
虽然v8有垃圾回收机制,但当进程不再需要某些内存时,如果这些内存数据仍然被其他对象引用着,v8的垃圾回收器就无法回收它们。这种情况被称为内存泄漏,它会导致内存持续增长。
默认情况下,64 位操作系统中 v8 可以申请 8GB 堆内存。然而,通过关闭指针压缩功能,可以突破这一限制。
"关闭 v8 指针压缩功能后,使用以下命令重新编译 Electron:
bash
cd src
set CHROMIUM_BUILDTOOLS_PATH=%cd%\buildtools
gn gen out/Release_disable_v8_pointer_compression --args=""import(\""//electron/build/args/release.gn\"")""
ninja -C out/Release_disable_v8_pointer_compression electron -j 4
编译成功后,v8 将能够突破 4GB 堆内存大小限制。"
"要关闭 v8 的指针压缩功能,可以在 src\electron\build\args\all.gn 文件中添加以下代码:
gn
# Disable pointer compression
v8_enable_pointer_compression = false
v8_enable_pointer_compression_shared_cage = false
同时,确保在 src\third_party\electron_node\deps\v8\BUILD.gn 文件中,将 v8_enable_pointer_compression 和 v8_enable_pointer_compression_shared_cage 变量都赋值为 false。"
由于 v8 指针压缩将堆内存大小限制为 4GB,为了突破这一限制,需要关闭指针压缩功能,允许 v8 申请更多的堆内存。