问题背景
最近在排查系统内存泄漏问题时,发现某个页面的内存占用颇高(500M+),且访问过这个页面后,后续进入的页面的内存开销也会增加大约400M左右,怀疑存在内存泄漏问题
排查记录
未进入目标页面前的内存数据
进入目标页面后的内存数据
反复进入目标页面,发现内存数据始终稳定在 520M ~ 540M 左右,录制内存快照
发现占用最高的是 svg 相关节点,分析页面代码,发现业务上使用img标签加载了一张svg格式的图片,而这张图片高达 18M
浏览器使用img加载svg资源,是需要解析的,而18M左右的svg资源解析消耗的内存高达400M左右,而且这部分资源消耗不会随着img节点的销毁而释放。
结合业务场景,该页面的访问是一个相对低频的操作,用户一旦访问过该页面,内存可能在用户关闭页面前持续高位,导致页面卡顿、甚至浏览器崩溃(尤其是低配设备或移动端),因此需要手动干预这部分内存的回收
解决方案
可以手动在组件销毁阶段将img.src属性置为空,浏览器就会释放svg解析消耗的这部分资源
javascript
<template>
<img
ref="imageRef"
:src="imageUrl"
:alt="altText"
class="large-image__img"
@load="handleImageLoad"
@error="handleImageError"
:style="{ maxWidth, maxHeight }"
/>
</template>
<scritp setup lang="ts">
import { onBeforeUnmount, useTemplateRef } from 'vue';
const imageRef = useTemplateRef<HTMLImageElement>('imageRef');
onBeforeUnmount(() => {
if (imageRef.value) {
imageRef.value.src = '';
}
});
</script>
后续的思考
浏览器对svg解析资源的缓存可能是在某些场景下的一种优化手段,但如果加载的svg较大 且用户访问较低频 ,还是用完就销毁为好。