内存泄漏问题
Opened this issue · 15 comments
在h5页面如果频繁调用动画,或者动画一直loop播放的话,会造成内存泄漏,页面直接卡死或者自动刷新页面。这个问题有什么解决办法吗?
最好提供一个最小复现,方便问题定位
这个问题我也遇到了 导致页面卡死
最好提供一个最小的恢复,方方便问题定位
`
import React, { memo, useRef, useEffect } from 'react';
import { Parser, Player } from 'svga';
const SvgaComponent = (props) => {
const { svgaUrl, loop = 1, onEnd, fillElement } = props;
const svgaRef = useRef(null);
const parserRef = useRef(null);
const playerRef = useRef(null);
useEffect(() => {
playAnimation();
return () => {
parserRef?.current?.destroy();
playerRef?.current?.destroy();
};
}, []);
const playAnimation = async () => {
try {
parserRef.current = new Parser();
const svga = await parserRef.current?.load(svgaUrl);
playerRef.current = new Player({
container: svgaRef.current,
loop: loop
});
// 需要填充的动态元素
for (const key in fillElement) {
if (Object.hasOwnProperty.call(fillElement, key)) {
const canvasEl = fillElement[key];
canvasEl && (svga.dynamicElements[key] = canvasEl);
}
}
await playerRef.current?.mount(svga);
} catch (error) {
console.error(error);
}
playerRef.current.onEnd = () => {
console.log('end');
onEnd?.();
};
// 开始播放动画
playerRef.current?.start();
};
return (
<canvas
style={{
width: '100%',
height: 'auto',
...props?.style
}}
ref={svgaRef}
></canvas>
);
};
export default memo(SvgaComponent);
`
这里是我封装的svga组件,我就是在外部进行调用此组件,动画可能是loop循环的,也可能是点击频繁播放的就会导致页面的卡顿白屏或者刷新
@codingJia 我对 react 不太熟悉,destroy 的部分会及时执行吗?
@codingJia 我对 react 不太熟悉,destroy 的部分会及时执行吗?
会的,每次都会销毁,不过如果是loop的播放就不会销毁了,因为他会一直执行动画。
在h5页面如果频繁调用动画,或者动画一直loop播放的话,会造成内存泄漏,页面直接卡死或者自动刷新页面。这个问题有什么解决办法吗?
这个确实是个bug,我试过很小的svga文件webview中循环播放,必现重刷,有时会webview崩掉。测试机型 iphone8p,系统16,我的解决方法是回退到1.3.1版本。。。。
测试用例最好避免使用上其他的框架,我提供了一个最小的 测试用例。大家可以看看有没有其他使用上的疑问。
通过这个测试用例,在浏览器端或者内存检查工具 memlab,暂无发现存在内存泄漏的情况。
通过 fork 这个最小的测试用例进行修改测试,如有发现其他出现内存泄漏的情况,麻烦带上重现用例 repo。
我在使用你提供的测试例子使用了区间在400到700kb上下的svga文件进行循环播放,在ios16.4版本中会出现播放卡死或者页面刷新现象。
shakeBoxSvga.svga.zip
这是我使用的svga文件
ME1686651546251.mp4
这是使用上边svga文件出现的页面刷新视频
这个问题在ios16.4.1上百分百复现(13pm,14pm均复现)开启isCacheFrames可以避免这个问题,个人认为是OffscreenCanvas导致的崩溃具体错误我还没抓到,如果要不开启缓存可尝试改写 player/index.ts drawFrame
不缓存没必要使用OffscreenCanvas进行离屏计算
` private drawFrame (frame: number): void {
if (this.videoEntity === undefined) throw new Error('Player VideoEntity undefined')
if (this.config.isUseIntersectionObserver && !this.isBeIntersection) return
this.clearContainer()
const context = this.config.container.getContext('2d')
if (context === null) throw new Error('Canvas Context cannot be null')
if (this.config.isCacheFrames && this.cacheFrames[frame] !== undefined) {
const ofsFrame = this.cacheFrames[frame]
// ImageData
// context.putImageData(ofsFrame, 0, 0)
context.drawImage(ofsFrame, 0, 0, ofsFrame.width, ofsFrame.height, 0, 0, ofsFrame.width, ofsFrame.height)
return
}
if(this.config.isCacheFrames) {
let ofsCanvas = this.ofsCanvas
// OffscreenCanvas 在 Firefox 浏览器无法被清理历史内容
if (window.OffscreenCanvas !== undefined && window.navigator.userAgent.includes('Firefox')) {
ofsCanvas = new window.OffscreenCanvas(this.config.container.width, this.config.container.height)
}
ofsCanvas.width = this.config.container.width
ofsCanvas.height = this.config.container.height
render(
ofsCanvas,
this.bitmapsCache,
this.videoEntity.dynamicElements,
this.videoEntity.replaceElements,
this.videoEntity,
this.currentFrame
)
context.drawImage(
ofsCanvas,
0, 0, ofsCanvas.width, ofsCanvas.height,
0, 0, ofsCanvas.width, ofsCanvas.height
)
// 把帧缓存起来
if ('toDataURL' in ofsCanvas) {
const ofsImageBase64 = ofsCanvas.toDataURL()
const ofsImage = new Image()
ofsImage.src = ofsImageBase64
this.cacheFrames[frame] = ofsImage
} else {
this.cacheFrames[frame] = ofsCanvas.transferToImageBitmap()
}
} else {
render(
this.config.container,
this.bitmapsCache,
this.videoEntity.dynamicElements,
this.videoEntity.replaceElements,
this.videoEntity,
this.currentFrame
)
}
}`
目前尝试使用 iPhone 12 mini / iOS 16.3.1 Safari 浏览器打开 testcase 没发现崩溃情况,同时使用 mac safari 进行 debug 也没发现内存泄漏的问题,后续尝试升级 iOS 16.5 再试试。
default.mp4
@wentoos 可否提个 PR,通过设置参数关闭使用 OffscreenCanvas?
@wentoos可以否提个PR,通过设置参数关闭使用OffscreenCanvas?
目前没抓到准确为OffscreenCanvas导致崩溃现场,debug时看不到堆栈,因为直接刷新了(我也很无奈,为了解决这个问题,我也是逐一排查的.....),mac 控制台工具也抓不到safari错误信息,可以知道的是 16.4.1必现,稍后我可以提交一个pr上去,最快速就是魔法一下 window.OffscreenCanvas = undefined 帮助大家先解决问题
如果是频繁去点击某个按钮来控制动画的显示隐藏(这里的显示隐藏指的是canvas元素在页面中被移除,svga也执行了销毁。)也会出现页面卡死的状态
svga的格式转换之后,用pag格式播放,解决大动画crash的问题,而且内存释放也没问题
的格式转换之后,用pag格式播放,解决大动画crash的问题,而且内存释放也
怎么转换呢,请问