Reputation: 195
I think that there is a problem with the disposing of BitmapFonts in LibGDX. I created this test:
printAnalytics();
ArrayList<BitmapFont> fonts = new ArrayList<BitmapFont>();
for (int i = 0; i < 2000; i++) {
// create a sample parameters
FreeTypeFontParameter params = new FreeTypeFontParameter();
params.size = 12;
params.minFilter = TextureFilter.Nearest;
params.magFilter = TextureFilter.Nearest;
// load the font
FileHandle fontFile = Gdx.files.internal("arial.ttf");
// generate it
FreeTypeFontGenerator generator = new FreeTypeFontGenerator(fontFile);
BitmapFont bitmapFont = generator.generateFont(params);
bitmapFont.setUseIntegerPositions(false);
generator.dispose();
// add to array
fonts.add(bitmapFont);
}
printAnalytics();
// dispose all fonts
for (BitmapFont font : fonts) {
font.dispose();
}
// clear array
fonts.clear();
fonts = null;
printAnalytics();
As you can see, I output some memory information before I load the fonts. Then I create 2 000 BitmapFonts and again output the info. Dispose the fonts, destroy the array (to lose all instances) and again memory info. I am using the default arial font for testing.
Here is the code of printAnalytics method:
public void printAnalytics() {
int mb = 1024 * 1024;
// get Runtime instance
Runtime instance = Runtime.getRuntime();
System.out.println("\n***** Heap utilization statistics [MB] *****\n");
// available memory
System.out.println("Total Memory: " + (instance.totalMemory() / mb));
// free memory
System.out.println("Free Memory: " + (instance.freeMemory() / mb));
// used memory
System.out.println("Used Memory: " + ((instance.totalMemory() - instance.freeMemory()) / mb));
// Maximum available memory
System.out.println("Max Memory: " + (instance.maxMemory() / mb));
// Gdx heap
System.out.println("Gdx Java Heap: " + (Gdx.app.getJavaHeap() / mb));
// Gdx heap
System.out.println("Gdx Native Heap: " + (Gdx.app.getNativeHeap() / mb));
}
Here is my output:
***** Heap utilization statistics [MB] *****
Total Memory: 120
Free Memory: 91
Used Memory: 28
Max Memory: 1790
Gdx Java Heap: 28
Gdx Native Heap: 28
***** Heap utilization statistics [MB] *****
Total Memory: 232
Free Memory: 109
Used Memory: 122
Max Memory: 1790
Gdx Java Heap: 122
Gdx Native Heap: 122
***** Heap utilization statistics [MB] *****
Total Memory: 232
Free Memory: 109
Used Memory: 122
Max Memory: 1790
Gdx Java Heap: 122
Gdx Native Heap: 122
And the numbers from the Task Manager:
You can see the problem: The used memory before and after this test should be the same. But it is not. It is +150/200 MB!
I checked if the BitmapFont owns the texture (font.ownsTexture()) and it is true, so the dispose method should dispose the created font texture too.
I know that the JVM uses some RAM, so this is why Task Manager shows bigger numbers than these from the code. But why at the end the used java heap is +94MB (122-28) and the process memory is +175MB (340-165)?
Am I loading or disposing things wrong? Is it the Java? Is it LibGDX? This is a serious problem, because in one part of my program I need to load and unload a lot of fonts...
Update:
I skipped the part with the array: I created the font bitmapFont and then immediately called bitmapFont.dispose() and bitmapFont=null. The process memory didn't change, the heap used space stayed the same too. Why?!
I am running on Windows 7, Java 7.
Upvotes: 4
Views: 611
Reputation: 460
Interesting question, I changed a bit your test, basically moved everything that doesn't belongs to the test itself, like font loading, parameters, outside the loop. I also added System.gc() calls before and after so we can see the real memory being used.
printAnalytics("before test");
Array<BitmapFont> fonts = new Array<BitmapFont>();
// create a sample parameters
FreeTypeFontGenerator.FreeTypeFontParameter params = new FreeTypeFontGenerator.FreeTypeFontParameter();
params.size = 12;
params.minFilter = Texture.TextureFilter.Nearest;
params.magFilter = Texture.TextureFilter.Nearest;
// load the font
FileHandle fontFile = Gdx.files.internal("arial.ttf");
for (int i = 0; i < 2000; i++) {
// generate it
FreeTypeFontGenerator generator = new FreeTypeFontGenerator(fontFile);
BitmapFont bitmapFont = generator.generateFont(params);
bitmapFont.setUseIntegerPositions(false);
generator.dispose();
// add to array
fonts.add(bitmapFont);
}
printAnalytics("before disposing, before first gc");
System.gc();
printAnalytics("before disposing, after first gc");
// dispose all fonts
for (BitmapFont font : fonts) {
font.dispose();
}
// clear array
fonts.clear();
printAnalytics("after disposing, before second gc");
System.gc();
printAnalytics("after disposing, after second gc");
I changed a bit your printAnalytics, so it also reports the current event being measured
public static void printAnalytics(String event) {
...
System.out.println("\n***** Heap utilization (" + event + ") statistics [MB] *****\n");
And here are my results:
***** Heap utilization (before test) statistics [MB] *****
Total Memory: 180
Free Memory: 165
Used Memory: 15
Max Memory: 2647
Gdx Java Heap: 15
Gdx Native Heap: 15
***** Heap utilization (before disposing, before first gc) statistics [MB] *****
Total Memory: 180
Free Memory: 101
Used Memory: 78
Max Memory: 2647
Gdx Java Heap: 78
Gdx Native Heap: 78
***** Heap utilization (before disposing, after first gc) statistics [MB] *****
Total Memory: 180
Free Memory: 132
Used Memory: 48
Max Memory: 2647
Gdx Java Heap: 48
Gdx Native Heap: 48
***** Heap utilization (after disposing, before second gc) statistics [MB] *****
Total Memory: 180
Free Memory: 131
Used Memory: 48
Max Memory: 2647
Gdx Java Heap: 48
Gdx Native Heap: 48
***** Heap utilization (after disposing, after second gc) statistics [MB] *****
Total Memory: 180
Free Memory: 178
Used Memory: 2
Max Memory: 2647
Gdx Java Heap: 2
Gdx Native Heap: 2
It seems like disposing makes a difference, but looks like java will make its decision about when that memory will be freed, unless you call System.gc()
Upvotes: 3