Does marking a seq of objects with destructors as `acyclic` prevent memory leaks in cyclic references?
0 reputation · 21 Dec 2025, 04:11 UTC
0 reputation · 21 Dec 2025, 04:11 UTC
The goal is to safely manage memory for a seq of objects that each define a =destroy destructor and may form reference cycles through their fields.
When using the default ORC garbage collector (--gc:orc), cycles containing seq or ref are not reclaimed automatically unless the type is marked with the acyclic pragma or the cycle collector is invoked manually. However, the documentation notes that acyclic suppresses cycle collection for the type, which can hide real leaks and may affect destructor ordering if the collector would have broken the cycle.
Does marking the seq type as acyclic guarantee that no memory leak occurs when the sequence participates in a cycle, or does it merely disable the collector and risk hiding leaks? Is there a recommended pattern (e.g., using DoublyLinkedList or explicit dealloc) that preserves deterministic destructor execution without leaks? How can one empirically verify that the chosen approach does not leak in long‑running server workloads?
32275 reputation · 21 Dec 2025, 10:23 UTC
No, marking a type as acyclic does not prevent memory leaks in cyclic references. In fact, it does the opposite: it instructs the garbage collector to skip cycle detection for that type. If a cycle actually exists, the collector will ignore it, and the objects—along with their =destroy destructors—will never be reclaimed, resulting in a permanent memory leak.
Under the ORC garbage collector, the acyclic pragma is an optimization hint. It tells the system: "This type is guaranteed never to be part of a reference cycle."
acyclic, it bypasses the expensive cycle-detection phase.seq as acyclic but it participates in a cycle (e.g., an element in the sequence holds a reference back to the sequence itself), the collector assumes no cycle exists. The reference counts will never reach zero, and the cycle collector will not intervene to break the loop.=destroy method is never called. This leads to both memory leaks and the failure to release any external resources (file handles, sockets) managed by the destructor.To ensure memory is reclaimed and destructors execute deterministically without relying on the non-deterministic cycle collector, consider these alternatives:
dealloc() or clear() method that explicitly breaks the cycles (setting references to null) before the object goes out of scope.DoublyLinkedList pattern where only the parent owns the children, and children use "weak" or non-owning references to the parent.acyclic and trigger the cycle collector manually at known safe points in the application lifecycle.To verify that your chosen approach does not leak in long-running workloads, use the following scoped verification steps:
=destroy method. If you drop all root references to a sequence but the log does not trigger, you have a leak.acyclic is masking a leak.acyclic pragma. If memory usage is lower without the pragma, the cycle collector was successfully reclaiming objects that acyclic was hiding.Missing Diagnostic Detail: To refine this recommendation, are the cycles created dynamically at runtime via user input, or are they static architectural relationships defined at compile time?
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.