I wouldn't be so quick to assume that reference counting requires less CPU cycles unless you have actual data to back up that claim.
With reference counting every single allocation, as well as every single object ownership transfer requires extra CPU cycles and memory accesses to manage the memory as well as manage the counter (yes, I know Swift does some clever tricks to avoid the counting which frankly is the only reason it's as performant as it is). Also remember multithreading issues when updating the refcounter.
With garbage collection, you obviously don't need to do any reference counter management, saving a lot of CPU and memory access cycles right there. But what is less obvious is that memory allocation itself is much faster with (compacting) garbage collector. After collection, all free memory will be in a single contiguous block, reducing the memory allocation operation to a single ADD instruction.
So, in summary:
With refcounting you have:
- Slow memory allocations (need to manage a fragmented heap)
- Slow accesses and pointer handovers (updates to the refcounter)
- Slow free (need to manage the free list)
- No asynchronous pauses (since there is no garbage collector)
With a GC, you get:
- Fast allocations (usually just an "add" instruction since the heap is not fragmented)
- Zero cost accesses and pointer handovers
- Zero cost free (just stop using the pointer)
- Some asynchronous pauses and CPU usage while running the GC
There have been plenty of research on memory management, and we're well past the time when you could say "GC is slower than the alternative".