Most Java apps create Java objects and then discard them rather quickly eg. you create some objects in a method then once you exit the method all the object dies. Most apps behave this way and most people tend to code their apps this way. The Java heap is roughly broken up into 3 parts, permanent, old (long lived) generation, and young (short lived) generation. Young gen is further broken up into S1, S2 and eden. These are just heaps.
Most objects when they are created in young gen. The idea here is that since the mortality rate of objects are high, we quickly create them, use them and then discard them. Speed is of essence. As you create object, the young gen fills up until a minor GC occurs. In minor GC, all objects that are alive are copied over from eden and say S2 to S1. Then the 'pointer' is rested on eden and S2.
Every copy ages the object. By default, if an object survives 32 copies viz. 32 minor GC, then the GC figures that it is going to around a lot longer. So what it does is it tenure it to old gen. Old gen is just one big space. When the old gen fills up, a full GC happens in the old gen. Because there is no other space to copy to, the GC has to compact. It is a lot slower than minor GC.
You can tune the tenuring parameter with
java -XX:MaxTenuringThreshold=16
if you know that you have lots of long lived objects. You can print the various age bucket of your app with
java -XX:-PrintTenuringDistribution