A new Test object is created on the heap. There is one reference that refers to this object. The reference itself is on stack.
> Test.Inner inner = test.new Inner();
A new Inner object is created on the heap. The reference variable "inner" lies on stack and refers to the Inner instance on the heap. The inner object has a reference to the Test object. Thus, note that the heap-based instance of Test has now two references referring to it - one on stack and other from within the instance of Inner.
Also note that the instance of the Test class doesNOT have a reference to the instance of the Inner class.
> test = null;
The stack reference no more refers to anything. Thus, the heap-based instance of Test has only one reference referring to it - the reference through the instance of Inner.
Neither Inner nor Test instance is eligible for GC - each of them has a reference referring to it.
Invokes print method on the instance of Inner referenced by the stack-based reference "inner".
As an aside, note that calling a garbage-collector on invoking System.gc() is not guaranteed.