Integrated Dynamics

Integrated Dynamics

88M Downloads

Duplicate Variable Invalidate Listeners registered when updating part offset

Yamazak-mc opened this issue Ā· 1 comments

commented

Issue type:

  • 🐌 Performance issue

Description:

When placing a variable card that depends on other variable IDs into a part offset slot, duplicate listeners are registered on the dependency variable’s invalidateListeners. Over long runtimes this accumulates and eventually consumes heap memory.

Steps to reproduce the problem:

  1. Prepare a part with an offset upgrade.
  2. Prepare these variable cards:
    • ID 1: Long(1)
    • ID 2: Cast Long to Integer (variable IDs: [1])
  3. Insert the card ID 2 into the part’s offset slot.
  4. Remove the card from the slot and re-insert it.

At step 3 the invalidateListener registered on ID 1 is not cleared; at step 4 an additional (duplicate) listener gets registered.
In many cases, this might not cause issues because once a variable is evaluated, I assume its listeners are all cleared. However, when duplicate listeners accumulate on constants like Long(1), memory usage can grow over time.


In my actual gameplay

My friend and I were playing a modpack where we had a variable card in the offset slot with an expression like:
offset = (Current time % N) + 1
After running the world for several hours we started to see lag spikes. Turns out Integer 1 had accumulated tons of duplicate listeners, which eventually filled up several GB of heap.


Analysis

The containsKey check in the part offset handler is failing every time because the variable argument is a different LazyExpression instance on each call — even though the logical expression id is the same.

Relevant code:

if (!this.offsetVariableListeners.containsKey(variable)) {
variable.addInvalidationListener(() -> {
this.offsetVariableListeners.remove(variable);
this.offsetVariableSlotDirty.add(slot);
});
this.offsetVariableListeners.put(variable, true);
}

I'm very new to Minecraft modding, so unfortunately I couldn't figure out a good solution to this problem.

Versions:

I tested the following versions, and the issue occurs in both:

1.20.1
  • This mod: 1.20.1-1.27.6
  • Cyclops Core: 1.20.1-1.20.1
  • Minecraft: 1.20.1
  • Forge: 47.4.0
1.21.1
  • This mod: 1.21.1-neoforge-1.27.9
  • Cyclops Core: 1.21.1-neoforge-1.26.2
  • Minecraft: 1.21.1
  • Neoforge: 21.1.209

Here is a heap dump from my testing:
Image

commented

Thanks for reporting!