From 39188235b82ce42a18683445f651b077c91c16fe Mon Sep 17 00:00:00 2001 From: Lignium Date: Wed, 11 Jan 2023 06:04:46 +0200 Subject: [PATCH 1/2] Fix block entity memory leak --- .../core/server/level/ServerLevelMixin.java | 25 +++++++++++++++++++ .../mixin/core/world/level/LevelMixin.java | 3 +++ 2 files changed, 28 insertions(+) diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/server/level/ServerLevelMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/server/level/ServerLevelMixin.java index e9aa32e9dcb..84ba1b9469e 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/server/level/ServerLevelMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/server/level/ServerLevelMixin.java @@ -47,6 +47,7 @@ import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.JukeboxBlockEntity; +import net.minecraft.world.level.block.entity.TickingBlockEntity; import net.minecraft.world.level.chunk.ChunkGenerator; import net.minecraft.world.level.dimension.DimensionType; import net.minecraft.world.level.gameevent.GameEvent; @@ -57,6 +58,7 @@ import net.minecraft.world.level.storage.ServerLevelData; import net.minecraft.world.level.storage.WorldData; import net.minecraft.world.ticks.LevelTicks; +import org.objectweb.asm.Opcodes; import org.spongepowered.api.ResourceKey; import org.spongepowered.api.Sponge; import org.spongepowered.api.block.BlockSnapshot; @@ -520,6 +522,29 @@ public void save(@Nullable final ProgressListener progress, final boolean flush, manager.add(pos, type); } + @Inject( + method = "tick", + at = @At( + value = "FIELD", + target = "Lnet/minecraft/server/level/ServerLevel;emptyTime:I", + opcode = Opcodes.PUTFIELD, + shift = At.Shift.AFTER + ) + ) + private void impl$unloadBlockEntities(final BooleanSupplier param0, final CallbackInfo ci) { + /* + * This code fixes block entity memory leak when the level hasn't online players + * and forced chunks. For the first 300 ticks the level can still clean up removed + * block entities on its own (ticks are performed for block entities). After it + * this mixin code is responsible for the subsequent unloading of block entities. + * Such a memory leak occurs when a plugin writes a lot of blocks, but the level + * is without players. + */ + if (this.emptyTime >= 300 && !this.blockEntityTickers.isEmpty()) { + blockEntityTickers.removeIf(TickingBlockEntity::isRemoved); + } + } + @Override public String toString() { final Optional worldTypeKey = RegistryTypes.WORLD_TYPE.get().findValueKey((WorldType) this.shadow$dimensionType()); diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/world/level/LevelMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/world/level/LevelMixin.java index e91dee6790f..7c4d704d682 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/world/level/LevelMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/world/level/LevelMixin.java @@ -40,6 +40,7 @@ import net.minecraft.world.level.Level; import net.minecraft.world.level.LevelAccessor; import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.entity.TickingBlockEntity; import net.minecraft.world.level.border.WorldBorder; import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.dimension.DimensionType; @@ -67,6 +68,7 @@ import org.spongepowered.common.util.DataUtil; import org.spongepowered.math.vector.Vector3d; +import java.util.List; import java.util.function.Predicate; @Mixin(net.minecraft.world.level.Level.class) @@ -78,6 +80,7 @@ public abstract class LevelMixin implements LevelBridge, LevelAccessor { @Shadow protected float rainLevel; @Shadow protected float oThunderLevel; @Shadow protected float thunderLevel; + @Shadow @Final protected List blockEntityTickers; @Shadow public abstract LevelData shadow$getLevelData(); @Shadow public abstract void shadow$updateSkyBrightness(); From 1e9327eeba57f0875857207d0cd66b37ca38e5dd Mon Sep 17 00:00:00 2001 From: Lignium <41531939+Lignium@users.noreply.github.com> Date: Fri, 13 Jan 2023 19:28:23 +0200 Subject: [PATCH 2/2] Update src/mixins/java/org/spongepowered/common/mixin/core/server/level/ServerLevelMixin.java Co-authored-by: Joni Aromaa --- .../common/mixin/core/server/level/ServerLevelMixin.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/server/level/ServerLevelMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/server/level/ServerLevelMixin.java index 84ba1b9469e..9c4fb4696cb 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/server/level/ServerLevelMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/server/level/ServerLevelMixin.java @@ -541,7 +541,7 @@ public void save(@Nullable final ProgressListener progress, final boolean flush, * is without players. */ if (this.emptyTime >= 300 && !this.blockEntityTickers.isEmpty()) { - blockEntityTickers.removeIf(TickingBlockEntity::isRemoved); + this.blockEntityTickers.removeIf(TickingBlockEntity::isRemoved); } }