The reason is, you are guessing it right, performance. Let me first explain why the survivor spaces exist at all. There are two primary garbage collector designs with respect to the essential concern of object relocation:
The copying collector can operate faster and can be efficiently parallelized, basically because it never overwrites any objects. It cannot achieve that without using one "active" and one "dormant" heap space, these two switching roles after each GC run.
Basic design of a copying collector
Note: what follows is not a description of HotSpot's actual GC, but rather those aspects of it which are a part of the original design as presented in a 1970 ACM paper by C.J. Cheney. HotSpot adds further refinements, one of which is the addition of the Eden space explained below.
When a copying collection procedure starts, there are two spaces involved:
- From space: a contiguous block of memory split into two regions:
- survivors from the last GC;
- new objects (created since last GC);
- To space: completely empty.
The task of the GC run is to identify all surviving objects in the From space and copy them into the To space.
As the To space is being built up, the From space will be completely evacuated and nothing needs to be written to it.
Copying GC is single pass
A key advantage of the copying collector is that it is single-pass: we just scan all the GC roots, copying all those objects, and then scan those objects for further references, copying all the referents. We never revisit any object and don't need any support memory structures. (Look
here for a good explanation of this).
Forward pointers
As each surviving object is relocated, the old location can be marked with a forwarding pointer and this information can then be efficiently used as the surviving objects are scanned for references to the relocated objects, and those references updated. The old reference points to the forward pointer so the new pointer value is just one lookup away.
Why the third space?
Your question, "why are there two survivor spaces?" would actually better be phrased, "why a separate Eden space?".
HotSpot has introduced the Eden space as an optimization which keeps the capacity of the new allocation region constant, betting on the outcome that a large proportion of the objects will immediately turn into garbage. You can look at Eden as a portion of memory shared between the two spaces—the portion that will probably get freed upon the next GC. This actually improves memory utilization.