How to detect PermGen free memory - java

What is the best way to work out the current PermGen usage in a Grails app?
I'm trying to do some graphing of
Runtime.getRuntime().freeMemory();
Runtime.getRuntime().totalMemory();
And I'd like to also measure the free PermGen space. Most of the search engine + Stack Overflow results on this matter are on handling the PermGenOutOfMemory-like errors, I'd just like to access the stats on these.

Just connect to it using JConsole or VisualVM. Theres no way for you to programmatically determine the PermGen size in your application. You can use the MemoryMXBean to do simple memory reporting, but stick to using the tools I mentioned to get a more detailed picture.

I guess you should try this
public class Main {
public static void main(final String[] args) {
final RuntimeMXBean memMXBean = ManagementFactory.getRuntimeMXBean();
final String prefix = "-XX:MaxPermSize=";
final List<String> jvmArgs = memMXBean.getInputArguments();
String maxPermSize = null;
for (final String jvmArg : jvmArgs) {
if (jvmArg.startsWith(prefix)) {
maxPermSize = jvmArg.substring(prefix.length());
break;
}
}
System.out.println("MaxPermSize is " + maxPermSize);
}
}

I think ManagementFactory could be the source, one of the pools returned from List getMemoryPoolMXBeans() should be PermGen.

Related

Is there any equivalent of Java Runtime Class in C#? [duplicate]

How can I get the available RAM or memory used by the application?
You can use:
Process proc = Process.GetCurrentProcess();
To get the current process and use:
proc.PrivateMemorySize64;
To get the private memory usage. For more information look at this link.
You might want to check the GC.GetTotalMemory method.
It retrieves the number of bytes currently thought to be allocated by the garbage collector.
System.Environment has WorkingSet-
a 64-bit signed integer containing the number of bytes of physical memory mapped to the process context.
In .NET Core 3.0 and later (aka .NET 5 and later), you can use GC.GetGCMemoryInfo to get information about memory used by the GC heap and how much memory the GC thinks is available. .NET internally uses this data to calculate memory pressure. The memory pressure is used to decide when to trim the System.Buffers.ArrayPool.
In addition to #JesperFyhrKnudsen's answer and #MathiasLykkegaardLorenzen's comment, you'd better dispose the returned Process after using it.
So, In order to dispose the Process, you could wrap it in a using scope or calling Dispose on the returned process (proc variable).
using scope:
var memory = 0.0;
using (Process proc = Process.GetCurrentProcess())
{
// The proc.PrivateMemorySize64 will returns the private memory usage in byte.
// Would like to Convert it to Megabyte? divide it by 2^20
memory = proc.PrivateMemorySize64 / (1024*1024);
}
Or Dispose method:
var memory = 0.0;
Process proc = Process.GetCurrentProcess();
memory = Math.Round(proc.PrivateMemorySize64 / (1024*1024), 2);
proc.Dispose();
Now you could use the memory variable which is converted to Megabyte.
Look here for details.
private PerformanceCounter cpuCounter;
private PerformanceCounter ramCounter;
public Form1()
{
InitializeComponent();
InitialiseCPUCounter();
InitializeRAMCounter();
updateTimer.Start();
}
private void updateTimer_Tick(object sender, EventArgs e)
{
this.textBox1.Text = "CPU Usage: " +
Convert.ToInt32(cpuCounter.NextValue()).ToString() +
"%";
this.textBox2.Text = Convert.ToInt32(ramCounter.NextValue()).ToString()+"Mb";
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void InitialiseCPUCounter()
{
cpuCounter = new PerformanceCounter(
"Processor",
"% Processor Time",
"_Total",
true
);
}
private void InitializeRAMCounter()
{
ramCounter = new PerformanceCounter("Memory", "Available MBytes", true);
}
If you get value as 0 it need to call NextValue() twice. Then it gives the actual value of CPU usage. See more details here.
For the complete system you can add the Microsoft.VisualBasic Framework as a reference;
Console.WriteLine("You have {0} bytes of RAM",
new Microsoft.VisualBasic.Devices.ComputerInfo().TotalPhysicalMemory);
Console.ReadLine();

Groovy TemplateEngines and OutOfMemory. Possible memory leak?

I am having some trouble in using the Groovy TemplateEngines in Java without running in OOM. When creating a lot of different templates it seems to me that there a lot of scripts created on the heap - which are then never garbage
collected.
I use java 8. When running this code with -Xmx32M there are about 3000 iterations possible. After that is a OOM-Error thrown.
Here is my code:
import groovy.text.SimpleTemplateEngine;
import groovy.text.Template;
import groovy.text.TemplateEngine;
import java.util.HashMap;
import java.util.Map;
public class Test {
public static void main(String[] args) throws Exception {
String groovy = "XX-${i}";
for (int i = 0; i < (1000000000); i++) {
TemplateEngine e = new SimpleTemplateEngine();
Template t = e.createTemplate(groovy);
Map<String, Object> binding = new HashMap<>();
binding.put("i", i);
String res = t.make(binding).toString();
if (i % 100 == 0) {
System.out.println("->" + res);
}
}
}
}
I also tried different variations and ClassLoaded - but in essence the results are always the same. As I can't find any current issues with that I guess I am missing something.
Could anyone help to enlighten me?
Tino
Here is your problem https://bugs.openjdk.java.net/browse/JDK-8037342.
Each time the parser runs it creates a new unique class based off the number of parse being done. For instance, after a while the class names look like
groovy.runtime.metaclass.SimpleTemplateScript4237MetaClass
groovy.runtime.metaclass.SimpleTemplateScript4238MetaClass
After a while the ClassLoader's parallelLockMap will fill the heap and nothing is eligible to be GC'd. It's sort of like a OOM PermGen error.
Use Apache Commons Text. Fast and Efficient alternative to SimpleTemplateEngine.
String templateString, Map binding;
StrSubstitutor sb = new StrSubstitutor(binding);
String value = sb.replace(templateString);
I have struggling with that problem has been a while and now I come up with that workaround.
Just call clear after run your script.
https://gist.github.com/jpozorio/38f26120e6346dfd74cecd7a147028aa

Java G1: Monitoring for memory leaks in production

For years, we've been running Java services with modest heap sizes using +UseParallelOldGC. Now, we're starting to roll out a new service using a larger heap and the G1 collector. This is going pretty well.
For our services that use +UseParallelOldGC, we monitor for memory leaks by looking at the old generation size after collection and alerting on a threshold. This works quite well, and in fact saved our bacon just two weeks ago.
Specifically, for +UseParallelOldGC, we do the following:
ManagementFactory.getMemoryPoolMXBeans()
Search for the MemoryPoolMXBean result with the name ending in "Old Gen"
Compare getCollectionUsage().getUsed() (if available) with getMax()
Unfortunately, it seems like G1 no longer has a concept of getCollectionUsage().
Fundamentally, though, we'd like to monitor the G1 heap size following the last mixed collection it chooses to do in a mixed cycle, or something similar.
For example, outside the VM I would be happy with an awk script that merely found the last '(mixed)' was that's followed by a '(young)' and look what the final heap size was (e.g., '1540.0M' 'Heap: 3694.5M(9216.0M)->1540.0M(9216.0M)')
Is there any way to do this inside the Java VM?
Yes, JVM gives you enough tools to retrieve such information for G1. For instance, you could use something like this class that prints all the details about garbage collections (just call MemoryUtil.startGCMonitor()):
public class MemoryUtil {
private static final Set<String> heapRegions;
static {
heapRegions = ManagementFactory.getMemoryPoolMXBeans().stream()
.filter(b -> b.getType() == MemoryType.HEAP)
.map(MemoryPoolMXBean::getName)
.collect(Collectors.toSet());
}
private static NotificationListener gcHandler = (notification, handback) -> {
if (notification.getType().equals(GarbageCollectionNotificationInfo.GARBAGE_COLLECTION_NOTIFICATION)) {
GarbageCollectionNotificationInfo gcInfo = GarbageCollectionNotificationInfo.from((CompositeData) notification.getUserData());
Map<String, MemoryUsage> memBefore = gcInfo.getGcInfo().getMemoryUsageBeforeGc();
Map<String, MemoryUsage> memAfter = gcInfo.getGcInfo().getMemoryUsageAfterGc();
StringBuilder sb = new StringBuilder(250);
sb.append("[").append(gcInfo.getGcAction()).append(" / ").append(gcInfo.getGcCause())
.append(" / ").append(gcInfo.getGcName()).append(" / (");
appendMemUsage(sb, memBefore);
sb.append(") -> (");
appendMemUsage(sb, memAfter);
sb.append("), ").append(gcInfo.getGcInfo().getDuration()).append(" ms]");
System.out.println(sb.toString());
}
};
public static void startGCMonitor() {
for(GarbageCollectorMXBean mBean: ManagementFactory.getGarbageCollectorMXBeans()) {
((NotificationEmitter) mBean).addNotificationListener(gcHandler, null, null);
}
}
public static void stopGCMonitor() {
for(GarbageCollectorMXBean mBean: ManagementFactory.getGarbageCollectorMXBeans()) {
try {
((NotificationEmitter) mBean).removeNotificationListener(gcHandler);
} catch(ListenerNotFoundException e) {
// Do nothing
}
}
}
private static void appendMemUsage(StringBuilder sb, Map<String, MemoryUsage> memUsage) {
memUsage.entrySet().forEach((entry) -> {
if (heapRegions.contains(entry.getKey())) {
sb.append(entry.getKey()).append(" used=").append(entry.getValue().getUsed() >> 10).append("K; ");
}
});
}
}
In this code, gcInfo.getGcAction() gives you enough information to separate minor collections from major/mixed ones.
But there's an important caveat to using your approach (with a threshold) to G1. A single mixed collection in G1 usually affects only several old gen regions - many enough to free sufficient amount of memory but not too many in order to keep the GC pause low. So, after a mixed collection in G1 you cannot be sure that all your garbage has gone. As a result, you need to find more sophisticated strategy to detect memory leaks (maybe based on collections frequency, gathering statistics from several collections, etc.)

How can I tell whether the JVM performed a garbage collection?

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.

Notification of memory shortage in Java

Is there any delivered feature in Java notifying a memory shortage in an application (or notifying that it has reach a predefined level)?
I was wondering whether it was possible to register a listener (or something equivalent) somewhere? I know about the memory methods in the Runtime class. I could create a scheduled task checking remaining memory myself, but I am wondering whether there is already an existing solution.
I don't think so, but I am looking for a confirmation.
FOR THE RECORDS
MemoryMXBean mbean = ManagementFactory.getMemoryMXBean();
NotificationEmitter emitter = (NotificationEmitter) mbean;
NotificationListener listener = new NotificationListener() {
#Override
public void handleNotification(Notification notif, Object handback) {
String notifType = notif.getType();
if (notifType.equals(MemoryNotificationInfo.MEMORY_THRESHOLD_EXCEEDED) ||
notifType.equals(MemoryNotificationInfo.MEMORY_COLLECTION_THRESHOLD_EXCEEDED)) {
// Retrieve the memory notification information
CompositeData cd = (CompositeData) notif.getUserData();
MemoryNotificationInfo info = MemoryNotificationInfo.from(cd);
MemoryUsage mu = info.getUsage();
System.out.println("Maximum memory = " + mu.getMax());
System.out.println("Used memory = " + mu.getUsed());
}
}
};
emitter.addNotificationListener(listener, null, null);
I believe you can set up a listener for a memory usage threshold using the MemoryMXBean. Sample code is provided in the javadoc link.

Categories