Skip to content

[BUG][1.21.1]Memory leak in VoxelShapeCache.mergeShapeCache (unbounded cache leads to OOM) #473

Open

Description

@1341254443

Description:

We are experiencing a severe memory leak on a modded Minecraft server (1.21.1) caused by the mergeShapeCache inside codechicken.lib.raytracer.VoxelShapeCache. The cache uses expireAfterAccess(2, HOURS) but no maximum size or weak reference, causing it to accumulate millions of ImmutableSet<VoxelShape> entries over time. Each entry holds VoxelShape objects which internally contain large double[] arrays (or DoubleArrayList), eventually consuming 90%+ of the heap (14+ GB) and causing server freezes / crashes.

Environment:

  • Minecraft version: 1.21.1
  • Mod loader: neoforge 21.1.221
  • CCL version: 4.6.1.526

Evidence:

1. Heap dump analysis (VisualVM)

  • double[] instances: 73.7 million (3.5 GB)
  • DoubleArrayList instances: 73.7 million (1.6 GB)
  • ArrayVoxelShape instances: 22 million (842 MB)
  • Heap usage: 14.2 GB / 15.6 GB (90.67%)

2. GC Root path (from VisualVM)

static mergeShapeCache in class codechicken.lib.raytracer.VoxelShapeCache
→ localCache (Guava LocalCache)
→ segments[]
→ table (AtomicReferenceArray)
→ StrongAccessEntry
→ key = ImmutableSet
→ value = merged VoxelShape
→ xs = double[] / DoubleArrayList

3. Code snippet (from current CCL version)

private static final Cache<ImmutableSet<VoxelShape>, VoxelShape> mergeShapeCache =
   CacheBuilder.newBuilder()
       .expireAfterAccess(2L, TimeUnit.HOURS)
       .build();

No maximumSize or weakValues is set.

Root cause:

mergeShapeCache never evicts entries as long as they are accessed every 2 hours. In a busy server, many distinct shape sets are constantly created, and the cache grows indefinitely.

Keys (ImmutableSet) strongly reference VoxelShape objects, which in turn hold large primitive arrays. This prevents GC from recovering memory.

The leak is amplified by mods that frequently call VoxelShapeCache.merge() (e.g., raytracing for entity culling, block rendering, or Translocators' pipe rendering).

Suggested fix:

Add a reasonable maximum size and/or use weak references:

private static final Cache<ImmutableSet<VoxelShape>, VoxelShape> mergeShapeCache =
    CacheBuilder.newBuilder()
        .maximumSize(5000)                         // limit number of entries
        .expireAfterAccess(1, TimeUnit.HOURS)      // shorter expiry
        .weakValues()                              // allow GC to collect values
        .build();

Alternatively, at least set .maximumSize(10000) to prevent unbounded growth.
Impact:

Without this fix, servers running any mod that uses CCL's VoxelShapeCache will eventually run out of memory, requiring frequent restarts.

Thank you for your great work!

Activity

  1. covers1624 commented on Apr 13, 2026

    @covers1624
    Member

    The voxel shape cache should never grow unboundedly, everywhere currently using this should be feeding in cached VoxelShape instances, misses should be infrequent.

    Do you have any reproduction steps for this? A known broken modpack? A world download?

    I beleve the caches could be reworked to set limits or weak values, or with some better profiling removed alltogether, its likely the merge cache isn't saving much time/memory (compared to the bb/cuboid -> shape cache). However, whatever is calling the merge api and cache missing should also be fixed first.

    Also, I'm concerned at the potential use of AI in your report. This issue has been filed on the Translocators repo not CodeChickenLib. You also mention that the leak is amplified by raytracing for entity culling, block rendering, or Translocators' pipe rendering, entity culling does not perform ray tracing, and Translocators does not contain any pipes. Using AI to analyse your heapdump is reasonable, however, please be aware it can hallucinate issues.

  2. 1341254443 commented on Apr 13, 2026

    @1341254443
    Author

    After I disabled Translocators and CodeChickenLib, the abnormal memory growth returned to normal.However, my production line may have stopped working due to the removal of Translocators, so the real issue might still be hidden.

    I'm not sure about the exact steps to reproduce the memory growth. Perhaps it's due to using a large number of fluid translocators and tanks to replace pipes. Even when I just let the game run idle after logging in, memory consumption increases rapidly. According to spark's memory report, I observed that the number of double[] instances kept growing until it reached 70 million. After I removed a large number of translocators, the memory growth rate decreased significantly. However, through spark I can still see that the above growth process is still happening.

    Modpack: Cook in Skyland Elegant Feast (0.6.0) – https://www.curseforge.com/minecraft/modpacks/cook-in-skyland-elegant-feast
    Extra mods I added: Spark (1.10.124), Tom's Simple Storage (1.21-2.3.0)
    I have also removed the Distant Horizons mod.
    World save: https://u.pcloud.link/publink/show?code=XZw1E65ZwXxhJFbpNUkMOLasY9LINLnzbfOX
    (Unfortunately, I no longer have the old world save where I was using a large number of transposers.)

    (Apologies if my use of AI caused any confusion – my computer skills are limited, so I rely on AI for help.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions