Some people argue (to death 😏) Reference Counting is not a Garbage Collection technique, but the GC Handbook lists it, discusses and compares, and that's the definitive reference. 😁
A unified theory of garbage collection paper goes a bit further and shows the duality between ("pure") tracing GC and RC, while collectors used in practice implement some "hybridisation" of both.
So we can establish the first dimension of the GC (design) space: on one side tracing GCs that traverse live objects, and opposite to them RC that traverses dead objects (imaging you have a huge tree with no links to nodes except from a parent node, and now the root of the tree becomes unreachable — reference counter goes 0, you deallocate the node and decrease counters of all it's children, which go 0 too, so you now have to deallocate them too, and so on until you traverse and deallocate all the now-garbage; while tracing GC would evacuate live objects and deallocate the whole region of memory regardless of which objects are dead inside it and how they are interconnected).
Another dimension is concurrency and parallelism, which are different notions. A parallel GC can use several cores at the same time to mark live objects and/or move/copy and/or free/compact memory. While concurrent GC can do that while program does it work and allocates new objects/forgets about the old ones. Concurrent GC might do that in a single thread or in a parallel fashion. There's also a notion of incrementality: incremental GC can do some work, then stop, then resume from the same spot. Some people use "concurrent" and "incremental" as synonyms — obviously, if you have an incremental GC you can turn it into concurrent by running preemptively with mutators.
But these are kinda internal GC properties, from an external point of view, the main characteristics of a GC are throughput, latency and space (overhead).
Throughput (as per usual) is how much garbage a collector can free per (sizeable) unit of time. It's very important if an application works in bursts allocating lots of temporary objects that need to be quickly freed before the next burst. Often Stop-the-World (STW) parallel collectors provide highest throughput.
Most usual throughput conflicts with latency i.e. how long a mutator thread have to wait for the GC to do its work before mutator can continue doing something useful. Modern GCs like the Java's Z and Shenandoha exhibit extremely low latencies.
Finally most GCs (RCs might show a counterexample) incur some memory overhead. The most obvious case is two-space copying collector that requires twice as much memory as the application otherwise would use.
And that's just the general very superficial picture, while there are lots of implementation details and programming language and application and workload specifics.
That said, I'd claim that well-designed and well-optimized tracing GC is overall more performant and beneficial that (general) reference counting. But very hard to implement. Still "serious languages" like Kotlin Native and AssemblyScript went from an RC to a tracing GC (somewhat recently).