Skip to content

InventoryAccessPort 每次 inventory 操作都重新 resolve handler,导致严重性能问题 #294

Description

@asqwrggp

InventoryAccessPortBlockEntity 的 InventoryAccessHandler 中,每个 IItemHandler 方法(getSlots、getStackInSlot、extractItem 等)都通过 getConnectedItemHandler() 重新调用 observedInventory.getInventory(),即每次都走一遍 LazyOptional 解析。

当 Create 的 Chute 连接 IAP 时,ItemHelper.extract 每 tick 遍历所有槽位,每个槽位触发多次 inventory 查询,每次都付出完整的解析开销。

性能数据(spark profiler,4000μs 采样间隔)
单个 Chute 连接 IAP(背后为 CombinedInvWrapper):~8ms/tick
IAP 相关帧累计 79 个,总耗时 18700μs(167s 采样内)
调用链:ChuteBlockEntity.tick → handleInput → ItemHelper.extract → IAP Handler → getConnectedItemHandler → LazyOptional.getValue(每次查询都走)
根因


private IItemHandler getConnectedItemHandler() {
    if (powered) return null;
    IItemHandler handler = observedInventory.getInventory(); // 每次调用都 resolve
    if (handler instanceof WrappedItemHandler) return null;
    return handler;
}

连接的容器在两次 updateConnectedInventory() 之间不会变化,无需每次重新 resolve。

次要问题
ThreadLocal recursionGuard:MC tick 是单线程的,普通 boolean 字段即可,省去每次调用 3 次 ThreadLocal 操作
preventRecursion 缺少 try-finally:若 value.get() 抛异常,guard 永远不释放
修复思路


// 1. 缓存 handler,仅在 updateConnectedInventory() 时标脏
private IItemHandler cachedHandler;
private boolean handlerDirty = true;

private IItemHandler getConnectedItemHandler() {
    if (powered) return null;
    if (handlerDirty) {
        IItemHandler h = observedInventory.getInventory();
        cachedHandler = (h instanceof WrappedItemHandler) ? null : h;
        handlerDirty = false;
    }
    return cachedHandler;
}

// 在 updateConnectedInventory() 开头:
handlerDirty = true;

// 2. ThreadLocal → boolean + try-finally
private boolean inRecursion = false;

private <T> T preventRecursion(Supplier<T> value, T defaultValue) {
    if (inRecursion) return defaultValue;
    inRecursion = true;
    try {
        return value.get();
    } finally {
        inRecursion = false;
    }
}

环境
Minecraft 1.20.1, Forge 47.4.10
Create 6.0.8, Create Connected 1.2.3
已在 GitHub main 分支确认问题仍存在

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