Skip to content

建议将永久保留历史GLID升级成延迟清除GLID以防止内存泄露 #147

@linfen0

Description

@linfen0

问题背景
当前 TextureTracker 的多张全局 Map 只增不减,历史 GLID 持续累积,导致 Java 堆内存与映射规模单调上升,并存在 updateMapping() 越界与性能退化风险。


完整闭环问题分析(按调用顺序)

  1. 纹理对象创建与 GLID 产生
    TextureUtil.generateTextureId() 被重定向到 TextureProxy.generateTextureId(),每次创建纹理对象都会生成新 GLID。
  • src/main/java/com/radiance/mixins/vulkan_render_integration/TextureUtilMixins.java:15
  • src/main/java/com/radiance/mixins/vulkan_render_integration/AbstractTextureMixins.java:65
  1. GLID 被记录进全局映射
    纹理分配与注册时,将新 GLID 写入 TextureTracker
  • src/main/java/com/radiance/mixins/vanilla_resource_tracker/TextureUtilMixins.java:23
  • src/main/java/com/radiance/mixins/vanilla_resource_tracker/TextureManagerMixins.java:17
  • src/main/java/com/radiance/client/texture/AuxiliaryTextures.java:170
  • src/main/java/com/radiance/client/texture/AuxiliaryTextures.java:173
  1. 每帧上传“全量历史映射”
    BufferProxy.updateMapping() 每帧遍历 GLID2* 并上传到 native。
  • src/main/java/com/radiance/mixins/vulkan_render_integration/WorldRendererMixins.java:342
  • src/main/java/com/radiance/client/proxy/vulkan/BufferProxy.java:437
  1. 清理链路被断开
    纹理的 clearGlId() 被取消,且 Java 层无 destroyTexture
  • src/main/java/com/radiance/mixins/vulkan_render_integration/AbstractTextureMixins.java:48
  • src/main/java/com/radiance/client/proxy/vulkan/TextureProxy.java:8
  • src/main/java/com/radiance/client/cloud/CloudTileManager.java:65
  1. 结果:历史 GLID 永久保留
    映射无限增长,updateMapping() 越界风险真实存在。
  • src/main/java/com/radiance/client/proxy/vulkan/BufferProxy.java:439

为什么“不敢立刻清理旧句柄”

  1. 旧几何数据仍可能引用旧 GLID
    Chunk/Entity 构建数据固化当时的 geometryTextureID,异步管线可能延迟数帧消费。
  • src/main/java/com/radiance/client/proxy/world/ChunkProxy.java:333
  • src/main/java/com/radiance/client/proxy/world/EntityProxy.java:1077
  1. 缺少 GPU 同步与销毁入口
    没有 destroyTexture 与 fence,立刻删除存在“在途帧引用失效”的风险。

结论:目前保留旧 GLID 是一种“保守安全策略”,但没有回收闭环导致永久累积。


改进建议(先稳住、再彻底)

阶段1:先稳住(仅 Java 侧延迟回收)
目标:立刻控制 Map 规模,避免无界增长。

  1. 为 GLID 维护 lastSeenFrame / retireFrame
  2. ChunkProxy / EntityProxy / AuxiliaryTextures 使用点标记活跃。
  3. TextureManagerMixins 发现同一 Identifier 绑定新 GLID 时,将旧 GLID 标记退休。
  4. BufferProxy.updateMapping() 前做 sweep:
  • 超过 INACTIVE_FRAMES → 进入退休
  • 超过 GRACE_FRAMES → 从所有 GLID2* 移除
  1. 频率建议:每 30 帧扫一次,GRACE_FRAMES=8~16

阶段2:再彻底(补 native 回收闭环)
目标:真正释放显存与原生资源。

  1. 新增 TextureProxy.destroyTexture(int id)
  2. Java 侧维护退休队列,记录 retireFrame
  3. 通过 GPU fence/帧完成信号确认无引用后再 destroy。
  4. 清理顺序:先销毁 auxGLID,再移除映射,再销毁主 GLID。

验收标准

  1. GLID2* 数量稳定在一个可预期上限内,不再随运行时间线性增长。
  2. updateMapping() 不再出现 sourceID >= 4096 异常。
  3. 长时间运行后内存曲线趋于稳定。

补充说明
这套回收策略与 DLSS/时域复用无直接依赖关系。DLSS/NRD/Temporal 依赖的是图像流(motion_vector/depth/history),与 GLID 映射表不是同一层的问题。

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions