A generational GC as the one in .NET allocates memory up-front, then passes out references/pointers from that allready allocated memory.
When the GC is getting close to the end of the pre-allocated memory, it will analyse all living objects (the objects it can reach from the stack and global variables, and objects referenced by those objects) and copies them over to a different area of memory (generation).
The area the memory was copied from, is now all garbage, and can be overwritten by new objects.
I guess you could say that instead of collecting garbage, it de-fragments your living objects.
If the GC still doesn’t have enough memory, it will try to allocate more.
In any case. The cost of a generational garbage collector is associated with living objects, not dead ones, so manually deleting doesn’t make sense.