问题背景
当前 TextureTracker 的多张全局 Map 只增不减,历史 GLID 持续累积,导致 Java 堆内存与映射规模单调上升,并存在 updateMapping() 越界与性能退化风险。
完整闭环问题分析(按调用顺序)
- 纹理对象创建与 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
- 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
- 每帧上传“全量历史映射”
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
- 清理链路被断开
纹理的 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
- 结果:历史 GLID 永久保留
映射无限增长,updateMapping() 越界风险真实存在。
src/main/java/com/radiance/client/proxy/vulkan/BufferProxy.java:439
为什么“不敢立刻清理旧句柄”
- 旧几何数据仍可能引用旧 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
- 缺少 GPU 同步与销毁入口
没有 destroyTexture 与 fence,立刻删除存在“在途帧引用失效”的风险。
结论:目前保留旧 GLID 是一种“保守安全策略”,但没有回收闭环导致永久累积。
改进建议(先稳住、再彻底)
阶段1:先稳住(仅 Java 侧延迟回收)
目标:立刻控制 Map 规模,避免无界增长。
- 为 GLID 维护
lastSeenFrame / retireFrame。
- 在
ChunkProxy / EntityProxy / AuxiliaryTextures 使用点标记活跃。
- 在
TextureManagerMixins 发现同一 Identifier 绑定新 GLID 时,将旧 GLID 标记退休。
- 在
BufferProxy.updateMapping() 前做 sweep:
- 超过
INACTIVE_FRAMES → 进入退休
- 超过
GRACE_FRAMES → 从所有 GLID2* 移除
- 频率建议:每 30 帧扫一次,
GRACE_FRAMES=8~16。
阶段2:再彻底(补 native 回收闭环)
目标:真正释放显存与原生资源。
- 新增
TextureProxy.destroyTexture(int id)。
- Java 侧维护退休队列,记录
retireFrame。
- 通过 GPU fence/帧完成信号确认无引用后再 destroy。
- 清理顺序:先销毁
auxGLID,再移除映射,再销毁主 GLID。
验收标准
GLID2* 数量稳定在一个可预期上限内,不再随运行时间线性增长。
updateMapping() 不再出现 sourceID >= 4096 异常。
- 长时间运行后内存曲线趋于稳定。
补充说明
这套回收策略与 DLSS/时域复用无直接依赖关系。DLSS/NRD/Temporal 依赖的是图像流(motion_vector/depth/history),与 GLID 映射表不是同一层的问题。
问题背景
当前
TextureTracker的多张全局Map只增不减,历史 GLID 持续累积,导致 Java 堆内存与映射规模单调上升,并存在updateMapping()越界与性能退化风险。完整闭环问题分析(按调用顺序)
TextureUtil.generateTextureId()被重定向到TextureProxy.generateTextureId(),每次创建纹理对象都会生成新 GLID。src/main/java/com/radiance/mixins/vulkan_render_integration/TextureUtilMixins.java:15src/main/java/com/radiance/mixins/vulkan_render_integration/AbstractTextureMixins.java:65纹理分配与注册时,将新 GLID 写入
TextureTracker。src/main/java/com/radiance/mixins/vanilla_resource_tracker/TextureUtilMixins.java:23src/main/java/com/radiance/mixins/vanilla_resource_tracker/TextureManagerMixins.java:17src/main/java/com/radiance/client/texture/AuxiliaryTextures.java:170src/main/java/com/radiance/client/texture/AuxiliaryTextures.java:173BufferProxy.updateMapping()每帧遍历GLID2*并上传到 native。src/main/java/com/radiance/mixins/vulkan_render_integration/WorldRendererMixins.java:342src/main/java/com/radiance/client/proxy/vulkan/BufferProxy.java:437纹理的
clearGlId()被取消,且 Java 层无destroyTexture。src/main/java/com/radiance/mixins/vulkan_render_integration/AbstractTextureMixins.java:48src/main/java/com/radiance/client/proxy/vulkan/TextureProxy.java:8src/main/java/com/radiance/client/cloud/CloudTileManager.java:65映射无限增长,
updateMapping()越界风险真实存在。src/main/java/com/radiance/client/proxy/vulkan/BufferProxy.java:439为什么“不敢立刻清理旧句柄”
Chunk/Entity 构建数据固化当时的
geometryTextureID,异步管线可能延迟数帧消费。src/main/java/com/radiance/client/proxy/world/ChunkProxy.java:333src/main/java/com/radiance/client/proxy/world/EntityProxy.java:1077没有
destroyTexture与 fence,立刻删除存在“在途帧引用失效”的风险。结论:目前保留旧 GLID 是一种“保守安全策略”,但没有回收闭环导致永久累积。
改进建议(先稳住、再彻底)
阶段1:先稳住(仅 Java 侧延迟回收)
目标:立刻控制 Map 规模,避免无界增长。
lastSeenFrame / retireFrame。ChunkProxy / EntityProxy / AuxiliaryTextures使用点标记活跃。TextureManagerMixins发现同一Identifier绑定新 GLID 时,将旧 GLID 标记退休。BufferProxy.updateMapping()前做 sweep:INACTIVE_FRAMES→ 进入退休GRACE_FRAMES→ 从所有GLID2*移除GRACE_FRAMES=8~16。阶段2:再彻底(补 native 回收闭环)
目标:真正释放显存与原生资源。
TextureProxy.destroyTexture(int id)。retireFrame。auxGLID,再移除映射,再销毁主 GLID。验收标准
GLID2*数量稳定在一个可预期上限内,不再随运行时间线性增长。updateMapping()不再出现sourceID >= 4096异常。补充说明
这套回收策略与 DLSS/时域复用无直接依赖关系。DLSS/NRD/Temporal 依赖的是图像流(
motion_vector/depth/history),与 GLID 映射表不是同一层的问题。