PixiJS中Graphics对象FillGradient内存泄漏问题求助
解决PixiJS中FillGradient内存泄漏问题
核心问题分析
每次调用drawBezierCurve时销毁并重建Graphics对象,结合FillGradient的使用会导致Pixi频繁生成新的渐变纹理,且旧纹理无法被垃圾回收(纯色填充无此问题是因为纯色不需要生成额外纹理)。频繁创建的纹理堆积最终导致内存溢出。
解决方案:复用Graphics对象,避免重复创建销毁
不需要每次重绘都销毁重建Graphics,直接复用现有对象并清空重绘即可,这样能避免渐变纹理的无意义创建。
修改后的代码示例
export class PixiCurve extends AContainerComponent { public curve = new Graphics(); container = new Container(); private pixiEdges: PixiEdges; private multiplierRef: MutableRefObject<number>; private gradientFill: FillGradient = new FillGradient(0, 0, 0, 0); constructor(pixiEdges: PixiEdges, multiplierRef: MutableRefObject<number>) { super(); this.pixiEdges = pixiEdges; this.multiplierRef = multiplierRef; this.gradientFill.x0 = this.pixiEdges.leftEdge; this.gradientFill.y1 = this.pixiEdges.bottomEdge; this.gradientFill.x1 = this.pixiEdges.leftEdge; this.gradientFill.addColorStop(0, new Color('#de3249')); this.gradientFill.addColorStop(1, new Color('#de324900')); this.curve.label = 'bezierCurve'; this.container.addChild(this.curve); // 初始化时只添加一次 } public drawBezierCurve(x: number, y: number) { this.curve.clear(); // 清空现有内容,复用Graphics // 绘制描边路径 this.curve.moveTo(this.pixiEdges.leftEdge, this.pixiEdges.bottomEdge); const controlX = this.pixiEdges.leftEdge + (x - this.pixiEdges.leftEdge) * 0.5; const controlY = this.pixiEdges.bottomEdge - this.multiplierRef.current; this.curve.quadraticCurveTo(controlX, controlY, x, y); this.curve.stroke({ color: 0xde3249, width: 2, alpha: 1 }); // 绘制填充路径 this.curve.moveTo(this.pixiEdges.leftEdge, this.pixiEdges.bottomEdge); this.curve.quadraticCurveTo(controlX, controlY, x, y); this.curve.lineTo(x, this.pixiEdges.bottomEdge); this.curve.lineTo(this.pixiEdges.leftEdge, this.pixiEdges.bottomEdge); this.gradientFill.y0 = y; this.curve.fill(this.gradientFill); } }
额外优化建议
- 合并路径命令:可以将描边和填充的路径合并,先绘制完整的闭合路径,再同时设置描边和填充,减少绘制指令,提升性能。
- 使用Shader实现渐变:如果渐变样式固定,使用自定义Shader实现渐变填充,完全避免纹理生成,从根源解决内存问题。思路是通过顶点着色器传递位置,片元着色器根据坐标计算渐变透明度。
替代填充方案:CanvasTexture预生成渐变
如果必须使用纹理式渐变,可以预先生成Canvas纹理并复用,动态更新渐变参数时重新绘制Canvas内容:
// 初始化时创建Canvas和纹理 private gradientCanvas = document.createElement('canvas'); private gradientTexture: Texture; constructor(pixiEdges: PixiEdges, multiplierRef: MutableRefObject<number>) { // ... 其他初始化代码 this.gradientCanvas.width = pixiEdges.rightEdge - pixiEdges.leftEdge; this.gradientCanvas.height = pixiEdges.bottomEdge - pixiEdges.topEdge; this.gradientTexture = Texture.from(this.gradientCanvas); } // 更新渐变时重绘Canvas private updateGradient(y: number) { const ctx = this.gradientCanvas.getContext('2d'); if (!ctx) return; const gradient = ctx.createLinearGradient(this.pixiEdges.leftEdge, y, this.pixiEdges.leftEdge, this.pixiEdges.bottomEdge); gradient.addColorStop(0, '#de3249'); gradient.addColorStop(1, '#de324900'); ctx.fillStyle = gradient; ctx.fillRect(0, 0, this.gradientCanvas.width, this.gradientCanvas.height); this.gradientTexture.update(); // 通知Pixi更新纹理 } // 绘制时用纹理填充路径 public drawBezierCurve(x: number, y: number) { this.curve.clear(); // ... 绘制路径 this.updateGradient(y); this.curve.fill(this.gradientTexture); }
内容的提问来源于stack exchange,提问作者Jan Vaculík
相关产品推荐
相关产品推荐

