{"record":{"id":"34b403b76b72b002","repo":"oracle/graal","slug":"allocator-s-housekeeping-thread-was-interrupted","errorCode":null,"errorMessage":"Allocator's housekeeping thread was interrupted.","messagePattern":"Allocator's housekeeping thread was interrupted\\.","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"sdk/src/org.graalvm.collections/src/org/graalvm/collections/LockFreePrefixTree.java","lineNumber":1119,"sourceCode":"                        hashChildrenPreallocationTotal[sizeClass] += growthEstimate;\n                    }\n                }\n            }\n\n            @Override\n            public void run() {\n                while (isEnabled.get()) {\n                    try {\n                        synchronized (this) {\n                            log(\"housekeeping thread sleeping... %d ms.\", nextHousekeepingPeriodMillis);\n                            this.wait(nextHousekeepingPeriodMillis);\n                            // Decrease housekeeping period up to maximum using an exponential\n                            // backoff.\n                            nextHousekeepingPeriodMillis = Math.min(defaultHousekeepingPeriodMillis, nextHousekeepingPeriodMillis * 2);\n                        }\n                        housekeep();\n                    } catch (InterruptedException e) {\n                        throw new RuntimeException(\"Allocator's housekeeping thread was interrupted.\", e);\n                    }\n                }\n            }\n        }\n    }\n}\n","sourceCodeStart":1101,"sourceCodeEnd":1126,"githubUrl":"https://github.com/oracle/graal/blob/a66e9ccd1d7bf2552883939aa0788dfd0e294aab/sdk/src/org.graalvm.collections/src/org/graalvm/collections/LockFreePrefixTree.java#L1101-L1126","documentation":"The ObjectPoolingAllocator's housekeeping thread runs a wait/housekeep loop; if the thread is interrupted while sleeping between housekeeping passes, the InterruptedException is wrapped in a RuntimeException and thrown, terminating the housekeeping thread. Pool pruning/cleanup then stops, which can let pooled memory accumulate until the allocator is shut down.","triggerScenarios":"Anything calling Thread.interrupt() on the allocator's housekeeping thread — executor shutdownNow(), application shutdown logic that interrupts all non-daemon threads, or aggressive thread management in tests/containers.","commonSituations":"Running inside application servers or test frameworks that bulk-interrupt threads on redeploy/shutdown; calling shutdown() concurrently with an external interrupt; misbehaving libraries that interrupt unknown threads.","solutions":["Do not interrupt the housekeeping thread directly; use shutdown() to stop it.","Isolate the allocator's threads from bulk interrupt sweeps (name threads and exempt them, or run the tree in a dedicated thread group).","If the exception surfaced during shutdown, treat it as benign but verify shutdown() completed; otherwise recreate the allocator instance."],"exampleFix":"// before\nThread.getAllStackTraces().keySet().forEach(Thread::interrupt); // hits housekeeping thread\n\n// after\nalloc.shutdown(); // the only supported way to stop housekeeping","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"// In supervising code: verify housekeeping stopped after any interrupt storm\ntry {\n    alloc.shutdown();\n} catch (RuntimeException e) {\n    if (!(e.getCause() instanceof InterruptedException)) throw e;\n    // benign only during teardown; otherwise recreate allocator\n}","preventionTips":["Never interrupt threads you do not own; use shutdown() to stop the allocator.","Name the allocator threads and exempt them from bulk interrupt sweeps.","Run tree teardown before framework-level thread interruption."],"tags":["graalvm","collections","concurrency","interrupt","prefix-tree"],"backgroundTag":null,"analyzedSha":"a66e9ccd1d7bf2552883939aa0788dfd0e294aab","analyzedAt":"2026-08-14T13:58:47.161Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}