【问题标题】:Java with LibGDX font memory leakJava 与 LibGDX 字体内存泄漏
【发布时间】:2016-04-20 18:13:05
【问题描述】:

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

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

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

这里是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));
}

这是我的输出:

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

还有来自任务管理器的数字:

  • 测试前: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 上运行。

【问题讨论】:

    标签: java memory memory-leaks libgdx


    【解决方案1】:

    有趣的问题,我对你的测试做了一些改动,基本上把所有不属于测试本身的东西,比如字体加载、参数,都移到了循环之外。我还在之前和之后添加了 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
    

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

    【讨论】:

    • 帅哥。我测试了它——你是对的,gc 完成了这项工作:) 奇怪的是任务管理器中的内存仍然保持不变——300MB
    猜你喜欢
    • 2016-09-29
    • 1970-01-01
    • 2015-07-20
    • 1970-01-01
    • 2015-02-26
    • 2016-03-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多