Let's assume you have developed an e-commerce application for an online store. Also, let's assume that each logged-in user has their own ShoppingBasket instance that holds the products that they add to their basket.
Say, a user has logged in today and is planning to buy a soap bar and a delicious pack of cookies. For this user, the application will create two Product instances, one for each chosen product, and add them to the products list of ShoppingBasket:
Just before visiting the checkout page, the user sees that Amazon offers the same cookies at a much better price and decides to remove the cookies from the basket. Technically, the application would remove the Product instance from the list of products. But from there on, the product instance representing Chocolate cookies is an orphan object. As there is no reference to it, it cannot be reached by the application:
After a while, JVM's GC kicks in and sees the Chocolate cookies object instance. It determines that the object cannot be reached in any way by the application anymore and therefore decides to remove it. The memory the object was using up will now be released:
There are several tricks to tame GC. One well-known trick when an application needs to work with lots of similar objects is to put these objects in a pool (list of objects). When an application needs an object, it simply gets one from the pool and modifies the object according to its needs. When it has finished and doesn't need the object anymore, it will put it back in the pool. Since these objects are always in the scope (when not used, in the pool, which the application can access), GC will not try to dispose of these objects.