Rewritten since everybody seems to be answering a different question:
How can I tell whether the JVM performed a garbage collection? Perhaps a System listener?
You can get the Garbage collection statistics via JMX. This is how jstat gets the information.
public static void main(String... args) throws IOException {
for (GarbageCollectorMXBean bean : ManagementFactory.getGarbageCollectorMXBeans()) {
System.out.println(toMap(bean).toString()
.replace("javax.management.openmbean.SimpleType", "ST")
.replace("java.lang.", ""));
}
}
public static Map<String, Object> toMap(Object o) {
LinkedHashMap<String, Object> map = new LinkedHashMap<>();
BeanInfo beanInfo = null;
try {
beanInfo = Introspector.getBeanInfo(o.getClass());
} catch (IntrospectionException e) {
throw new RuntimeException(e);
}
for (PropertyDescriptor propertyDescriptor : beanInfo.getPropertyDescriptors()) {
if (propertyDescriptor.getName().equals("class")) continue;
Object value = null;
try {
value = propertyDescriptor.getReadMethod().invoke(o);
} catch (Exception e) {
value = e.toString();
}
map.put(propertyDescriptor.getName(), value);
}
return map;
}
prints a lot of descriptive information, but hidden in there is all the stats of how many collections have been performed, how long they took and the size of the regions before and after collections.
In particular, you can look at the collectionCount. When this increases, a collection occurred.
{collectionCount=2, collectionTime=1, lastGcInfo=javax.management.openmbean.CompositeDataSupport(compositeType=javax.management.openmbean.CompositeType(name=sun.management.PS Scavenge.GcInfoCompositeType,items=((itemName=GcThreadCount,itemType=ST(name=Integer)),(itemName=duration,itemType=ST(name=Long)),(itemName=endTime,itemType=ST(name=Long)),(itemName=id,itemType=ST(name=Long)),(itemName=memoryUsageAfterGc,itemType=javax.management.openmbean.TabularType(name=Map,rowType=javax.management.openmbean.CompositeType(name=Map,items=((itemName=key,itemType=ST(name=String)),(itemName=value,itemType=javax.management.openmbean.CompositeType(name=management.MemoryUsage,items=((itemName=committed,itemType=ST(name=Long)),(itemName=init,itemType=ST(name=Long)),(itemName=max,itemType=ST(name=Long)),(itemName=used,itemType=ST(name=Long))))))),indexNames=(key))),(itemName=memoryUsageBeforeGc,itemType=javax.management.openmbean.TabularType(name=Map,rowType=javax.management.openmbean.CompositeType(name=Map,items=((itemName=key,itemType=ST(name=String)),(itemName=value,itemType=javax.management.openmbean.CompositeType(name=management.MemoryUsage,items=((itemName=committed,itemType=ST(name=Long)),(itemName=init,itemType=ST(name=Long)),(itemName=max,itemType=ST(name=Long)),(itemName=used,itemType=ST(name=Long))))))),indexNames=(key))),(itemName=startTime,itemType=ST(name=Long)))),contents={GcThreadCount=10, duration=1, endTime=40, id=2, memoryUsageAfterGc=javax.management.openmbean.TabularDataSupport(tabularType=javax.management.openmbean.TabularType(name=Map,rowType=javax.management.openmbean.CompositeType(name=Map,items=((itemName=key,itemType=ST(name=String)),(itemName=value,itemType=javax.management.openmbean.CompositeType(name=management.MemoryUsage,items=((itemName=committed,itemType=ST(name=Long)),(itemName=init,itemType=ST(name=Long)),(itemName=max,itemType=ST(name=Long)),(itemName=used,itemType=ST(name=Long))))))),indexNames=(key)),contents={[Compressed Class Space]=javax.management.openmbean.CompositeDataSupport(compositeType=javax.management.openmbean.CompositeType(name=Map,items=((itemName=key,itemType=ST(name=String)),(itemName=value,itemType=javax.management.openmbean.CompositeType(name=management.MemoryUsage,items=((itemName=committed,itemType=ST(name=Long)),(itemName=init,itemType=ST(name=Long)),(itemName=max,itemType=ST(name=Long)),(itemName=used,itemType=ST(name=Long))))))),contents={key=Compressed Class Space, value=javax.management.openmbean.CompositeDataSupport(compositeType=javax.management.openmbean.CompositeType(name=management.MemoryUsage,items=((itemName=committed,itemType=ST(name=Long)),(itemName=init,itemType=ST(name=Long)),(itemName=max,itemType=ST(name=Long)),(itemName=used,itemType=ST(name=Long)))),contents={committed=524288, init=0, max=1073741824, used=424552})}), [PS Survivor Space]=javax.management.openmbean.CompositeDataSupport(compositeType=javax.management.openmbean.CompositeType(name=Map,items=((itemName=key,itemType=ST(name=String)),(itemName=value,itemType=javax.management.openmbean.CompositeType(name=management.MemoryUsage,items=((itemName=committed,itemType=ST(name=Long)),(itemName=init,itemType=ST(name=Long)),(itemName=max,itemType=ST(name=Long)),(itemName=used,itemType=ST(name=Long))))))),contents={key=PS Survivor Space, value=javax.management.openmbean.CompositeDataSupport(compositeType=javax.management.openmbean.CompositeType(name=management.MemoryUsage,items=((itemName=committed,itemType=ST(name=Long)),(itemName=init,itemType=ST(name=Long)),(itemName=max,itemType=ST(name=Long)),(itemName=used,itemType=ST(name=Long)))),contents={committed=524288, init=524288, max=524288, used=507920})}), [PS Old Gen]=javax.management.openmbean.CompositeDataSupport(compositeType=javax.management.openmbean.CompositeType(name=Map,items=((itemName=key,itemType=ST(name=String)),(itemName=value,itemType=javax.management.openmbean.CompositeType(name=management.MemoryUsage,items=((itemName=committed,itemType=ST(name=Long)),(itemName=init,itemType=ST(name=Long)),(itemName=max,itemType=ST(name=Long)),(itemName=used,itemType=ST(name=Long))))))),contents={key=PS Old Gen, value=javax.management.openmbean.CompositeDataSupport(compositeType=javax.management.openmbean.CompositeType(name=management.MemoryUsage,items=((itemName=committed,itemType=ST(name=Long)),(itemName=init,itemType=ST(name=Long)),(itemName=max,itemType=ST(name=Long)),(itemName=used,itemType=ST(name=Long)))),contents={committed=22544384, init=22544384, max=22544384, used=151568})}), [Metaspace]=javax.management.openmbean.CompositeDataSupport(compositeType=javax.management.openmbean.CompositeType(name=Map,items=((itemName=key,itemType=ST(name=String)),(itemName=value,itemType=javax.management.openmbean.CompositeType(name=management.MemoryUsage,items=((itemName=committed,itemType=ST(name=Long)),(itemName=init,itemType=ST(name=Long)),(itemName=max,itemType=ST(name=Long)),(itemName=used,itemType=ST(name=Long))))))),contents={key=Metaspace, value=javax.management.openmbean.CompositeDataSupport(compositeType=javax.management.openmbean.CompositeType(name=management.MemoryUsage,items=((itemName=committed,itemType=ST(name=Long)),(itemName=init,itemType=ST(name=Long)),(itemName=max,itemType=ST(name=Long)),(itemName=used,itemType=ST(name=Long)))),contents={committed=4980736, init=0, max=-1, used=3648080})}), [PS Eden Space]=javax.management.openmbean.CompositeDataSupport(compositeType=javax.management.openmbean.CompositeType(name=Map,items=((itemName=key,itemType=ST(name=String)),(itemName=value,itemType=javax.management.openmbean.CompositeType(name=management.MemoryUsage,items=((itemName=committed,itemType=ST(name=Long)),(itemName=init,itemType=ST(name=Long)),(itemName=max,itemType=ST(name=Long)),(itemName=used,itemType=ST(name=Long))))))),contents={key=PS Eden Space, value=javax.management.openmbean.CompositeDataSupport(compositeType=javax.management.openmbean.CompositeType(name=management.MemoryUsage,items=((itemName=committed,itemType=ST(name=Long)),(itemName=init,itemType=ST(name=Long)),(itemName=max,itemType=ST(name=Long)),(itemName=used,itemType=ST(name=Long)))),contents={committed=1048576, init=524288, max=9961472, used=0})}), [Code Cache]=javax.management.openmbean.CompositeDataSupport(compositeType=javax.management.openmbean.CompositeType(name=Map,items=((itemName=key,itemType=ST(name=String)),(itemName=value,itemType=javax.management.openmbean.CompositeType(name=management.MemoryUsage,items=((itemName=committed,itemType=ST(name=Long)),(itemName=init,itemType=ST(name=Long)),(itemName=max,itemType=ST(name=Long)),(itemName=used,itemType=ST(name=Long))))))),contents={key=Code Cache, value=javax.management.openmbean.CompositeDataSupport(compositeType=javax.management.openmbean.CompositeType(name=management.MemoryUsage,items=((itemName=committed,itemType=ST(name=Long)),(itemName=init,itemType=ST(name=Long)),(itemName=max,itemType=ST(name=Long)),(itemName=used,itemType=ST(name=Long)))),contents={committed=2555904, init=2555904, max=251658240, used=1242560})})}), memoryUsageBeforeGc=javax.management.openmbean.TabularDataSupport(tabularType=javax.management.openmbean.TabularType(name=Map,rowType=javax.management.openmbean.CompositeType(name=Map,items=((itemName=key,itemType=ST(name=String)),(itemName=value,itemType=javax.management.openmbean.CompositeType(name=management.MemoryUsage,items=((itemName=committed,itemType=ST(name=Long)),(itemName=init,itemType=ST(name=Long)),(itemName=max,itemType=ST(name=Long)),(itemName=used,itemType=ST(name=Long))))))),indexNames=(key)),contents={[Compressed Class Space]=javax.management.openmbean.CompositeDataSupport(compositeType=javax.management.openmbean.CompositeType(name=Map,items=((itemName=key,itemType=ST(name=String)),(itemName=value,itemType=javax.management.openmbean.CompositeType(name=management.MemoryUsage,items=((itemName=committed,itemType=ST(name=Long)),(itemName=init,itemType=ST(name=Long)),(itemName=max,itemType=ST(name=Long)),(itemName=used,itemType=ST(name=Long))))))),contents={key=Compressed Class Space, value=javax.management.openmbean.CompositeDataSupport(compositeType=javax.management.openmbean.CompositeType(name=management.MemoryUsage,items=((itemName=committed,itemType=ST(name=Long)),(itemName=init,itemType=ST(name=Long)),(itemName=max,itemType=ST(name=Long)),(itemName=used,itemType=ST(name=Long)))),contents={committed=524288, init=0, max=1073741824, used=424552})}), [PS Survivor Space]=javax.management.openmbean.CompositeDataSupport(compositeType=javax.management.openmbean.CompositeType(name=Map,items=((itemName=key,itemType=ST(name=String)),(itemName=value,itemType=javax.management.openmbean.CompositeType(name=management.MemoryUsage,items=((itemName=committed,itemType=ST(name=Long)),(itemName=init,itemType=ST(name=Long)),(itemName=max,itemType=ST(name=Long)),(itemName=used,itemType=ST(name=Long))))))),contents={key=PS Survivor Space, value=javax.management.openmbean.CompositeDataSupport(compositeType=javax.management.openmbean.CompositeType(name=management.MemoryUsage,items=((itemName=committed,itemType=ST(name=Long)),(itemName=init,itemType=ST(name=Long)),(itemName=max,itemType=ST(name=Long)),(itemName=used,itemType=ST(name=Long)))),contents={committed=524288, init=524288, max=524288, used=524288})}), [PS Old Gen]=javax.management.openmbean.CompositeDataSupport(compositeType=javax.management.openmbean.CompositeType(name=Map,items=((itemName=key,itemType=ST(name=String)),(itemName=value,itemType=javax.management.openmbean.CompositeType(name=management.MemoryUsage,items=((itemName=committed,itemType=ST(name=Long)),(itemName=init,itemType=ST(name=Long)),(itemName=max,itemType=ST(name=Long)),(itemName=used,itemType=ST(name=Long))))))),contents={key=PS Old Gen, value=javax.management.openmbean.CompositeDataSupport(compositeType=javax.management.openmbean.CompositeType(name=management.MemoryUsage,items=((itemName=committed,itemType=ST(name=Long)),(itemName=init,itemType=ST(name=Long)),(itemName=max,itemType=ST(name=Long)),(itemName=used,itemType=ST(name=Long)))),contents={committed=22544384, init=22544384, max=22544384, used=8192})}), [Metaspace]=javax.management.openmbean.CompositeDataSupport(compositeType=javax.management.openmbean.CompositeType(name=Map,items=((itemName=key,itemType=ST(name=String)),(itemName=value,itemType=javax.management.openmbean.CompositeType(name=management.MemoryUsage,items=((itemName=committed,itemType=ST(name=Long)),(itemName=init,itemType=ST(name=Long)),(itemName=max,itemType=ST(name=Long)),(itemName=used,itemType=ST(name=Long))))))),contents={key=Metaspace, value=javax.management.openmbean.CompositeDataSupport(compositeType=javax.management.openmbean.CompositeType(name=management.MemoryUsage,items=((itemName=committed,itemType=ST(name=Long)),(itemName=init,itemType=ST(name=Long)),(itemName=max,itemType=ST(name=Long)),(itemName=used,itemType=ST(name=Long)))),contents={committed=4980736, init=0, max=-1, used=3648080})}), [PS Eden Space]=javax.management.openmbean.CompositeDataSupport(compositeType=javax.management.openmbean.CompositeType(name=Map,items=((itemName=key,itemType=ST(name=String)),(itemName=value,itemType=javax.management.openmbean.CompositeType(name=management.MemoryUsage,items=((itemName=committed,itemType=ST(name=Long)),(itemName=init,itemType=ST(name=Long)),(itemName=max,itemType=ST(name=Long)),(itemName=used,itemType=ST(name=Long))))))),contents={key=PS Eden Space, value=javax.management.openmbean.CompositeDataSupport(compositeType=javax.management.openmbean.CompositeType(name=management.MemoryUsage,items=((itemName=committed,itemType=ST(name=Long)),(itemName=init,itemType=ST(name=Long)),(itemName=max,itemType=ST(name=Long)),(itemName=used,itemType=ST(name=Long)))),contents={committed=524288, init=524288, max=9961472, used=524288})}), [Code Cache]=javax.management.openmbean.CompositeDataSupport(compositeType=javax.management.openmbean.CompositeType(name=Map,items=((itemName=key,itemType=ST(name=String)),(itemName=value,itemType=javax.management.openmbean.CompositeType(name=management.MemoryUsage,items=((itemName=committed,itemType=ST(name=Long)),(itemName=init,itemType=ST(name=Long)),(itemName=max,itemType=ST(name=Long)),(itemName=used,itemType=ST(name=Long))))))),contents={key=Code Cache, value=javax.management.openmbean.CompositeDataSupport(compositeType=javax.management.openmbean.CompositeType(name=management.MemoryUsage,items=((itemName=committed,itemType=ST(name=Long)),(itemName=init,itemType=ST(name=Long)),(itemName=max,itemType=ST(name=Long)),(itemName=used,itemType=ST(name=Long)))),contents={committed=2555904, init=2555904, max=251658240, used=1242560})})}), startTime=39}), memoryPoolNames=[LString;#6d03e736, name=PS Scavenge, notificationInfo=[Ljavax.management.MBeanNotificationInfo;#568db2f2, objectName=java.lang:type=GarbageCollector,name=PS Scavenge, valid=true}
{collectionCount=0, collectionTime=0, lastGcInfo=null, memoryPoolNames=[LString;#378bf509, name=PS MarkSweep, notificationInfo=[Ljavax.management.MBeanNotificationInfo;#5fd0d5ae, objectName=java.lang:type=GarbageCollector,name=PS MarkSweep, valid=true}
GC is hardly going to affect your game performance, because it's ongoing, it keeps collecting everything that isn't used anymore and it does it while the code is running. You can force the GC to work and then put up a loading screen, but that's not recommended.
PS.: If the GC affected the game performance that much, Minecraft would be a disaster and Android apps and games wouldn't be built in Java! Think about that ;)
System.gc();
Java uses managed memory although I would not recommend you to use the above method.
From the Java Docs
Calling the gc method suggests that the Java Virtual Machine expend
effort toward recycling unused objects in order to make the memory
they currently occupy available for quick reuse. When control returns
from the method call, the Java Virtual Machine has made a best effort
to reclaim space from all discarded objects.