Java与LibGDX字体内存泄漏

时间:2016-04-20 18:13:05

标签: java memory memory-leaks libgdx

我认为在LibGDX中处理BitmapFonts存在问题。 我创建了这个测试:

gcloud preview app deploy

正如您所看到的,我在加载字体之前输出了一些内存信息。然后我创建2 000个BitmapFonts并再次输出信息。处理字体,销毁数组(丢失所有实例)和内存信息。 我使用默认的arial字体进行测试。

以下是printAnalytics方法的代码:

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();

这是我的输出:

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));
}

来自任务管理器的数字:

  • 测试前:165 MB (我在其中一个应用上测试)
  • 加载字体后:800 MB
  • 处置后:340 MB

您可以看到问题:此测试之前和之后使用的内存应该相同。但事实并非如此。它是+150/200 MB!

我检查了BitmapFont是否拥有纹理(font.ownsTexture()),这是真的,所以dispose方法也应该处理创建的字体纹理。

我知道JVM使用了一些RAM,所以这就是为什么任务管理器显示比代码更大的数字。但是为什么最后使用的java堆是+ 94MB (122-28),进程内存是+ 175MB (340-165)

我装错或丢错了吗?是Java吗?它是LibGDX吗?这是一个严重的问题,因为在我的程序的一部分我需要加载和卸载很多字体......

更新

我跳过了数组的部分:我创建了字体 bitmapFont ,然后立即调用 bitmapFont.dispose() bitmapFont = null 。进程内存没有改变,堆使用空间也保持不变。为什么呢?!

我在Windows 7,Java 7上运行。

1 个答案:

答案 0 :(得分:3)

有趣的问题,我改变了一点你的测试,基本上移动了所有不属于测试本身的东西,比如字体加载,参数,循环外。我之前和之后都添加了System.gc()调用,因此我们可以看到正在使用的实际内存。

            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");

我改变了一下printAnalytics,因此它还会报告当前正在测量的事件

    public static void printAnalytics(String event) {
        ...
        System.out.println("\n***** Heap utilization (" + event + ") statistics [MB] *****\n");

以下是我的结果:

***** 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

似乎处理有所作为,但看起来java将决定何时释放该内存,除非你调用System.gc()