Reputation: 2211
I have a JavaFX application that display a TabPane with multiple Tabs, like a normal browser.
I usually load some grids inside these Tabs. Every time a tab is selected, the old tab content is trashed and the new tab is loaded (from a server).
The problem is when you click on the old tab, you have to wait before it's loaded again. I want to have the same behavior as modern browser, and save the content in my application. The problem is, I don't know how much memory is given to my application, and how much tab can be opened.
Basically, what I'm doing is checking how much memory I have left (by following this answer Java get available memory ), and if I'm short, I just release all the tab content. Therefore, my application is able to run with 800Mo of memory, but if someone have 6Go of memory, the experience will be better.
At the end of the memory release process, I manually call the garbage collector because I've seen that releasing my tab content (allowing them to be garbage collected) is not immediate. I know it's bad, but on another hand, I don't rely on the garbage collector. If it's not called, it's not a problem, my tab's content will be collected at some point. Here is the so called method :
/**
* Before an action that may take some memory, we check how much memory we
* have left. If memory is short, we go through the Tab in order to release
* them if possible.
*/
public void verifyMemory() {
long allocatedMemory = (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory());
long memoryLeft = Runtime.getRuntime().maxMemory() - allocatedMemory;
System.out.println(memoryLeft/1000000);
//We must release some memory
if (memoryLeft < MEMORY_TRESHOLD) {
LOGGER.warn("Memory treshold is hit, we must release memory");
for (Tab tab : getTabs()) {
if (tab instanceof MyTab) {
((MyTab) tab).destroyIfPossible();
}
}
System.gc();
}
}
Do you have strong advice against my solution? Or any ideas that could improve or help me achieving my goal?
Upvotes: 3
Views: 644
Reputation: 49744
The standard way to deal with this scenario is to build a cache that uses SoftReference
s to keep unused objects in the cache until the GC decides it absolutely has to free up that memory.
The exact behaviour can be tuned (slightly awkwardly) via the -XX:SoftRefLRUPolicyMSPerMB
option, but the basic principle is that the more free memory is available, the longer softly referenced objects are preserved. (Unlike weak references, which are cleared out at the first opportunity.)
(Please note that there are several issues with SoftReference
that limit their usefulness as a general cache solution: for example the fact that they are shared across the entire VM, or that they require at least two GC cycles to clear. But they are ideal for caching a few massive objects in a standalone application.)
Guava's CacheBuilder
for example offers to create you just that sort of cache.
Upvotes: 2