Reference counting generally suffers from the cyclic reference problem, e.g. if you lose a reference to a doubly-linked-list, the entire data structure leaks and won&#x27;t get freed. In Obj-C, this problem is tackled via manually annotating some pointers as &quot;weak&quot;, explicitly (and you have to be extra careful with them).<p>There are less fundamental issues as well, like high contention on the reference count in highly parallel environments, and more memory fragmentation compared to a compacting garbage collector. Also, memory allocation tends to be faster on a compacting garbage collected heap (simply increment the heap pointer instead of searching for a large enough available block). Additionally, freeing memory when things run out of scope cause challenges when optimizing code, like making it more difficult to optimize function invocations that otherwise would have been eliminated as tail calls with a garbage collector. In practice, in some cases, the cost of a tracing garbage collector might be well worth when you amortize it over the lifetime of the program, compared to keeping track of reference counts at runtime.