You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 20:13:17