Skip to content

FileHandle#exists() doesn't close resource on iOS #2345

@dermetfan

Description

@dermetfan

Calling FileHandle#exists() (internal file) on iOS seems to forget closing a resource.

When I launch the iOS version of the app with i18n installed, I get this trace. It seems to run, correctly, but I'm guessing there should be a close in there somewhere...

[WARN] android.System: A resource was acquired at attached stack trace but never released. See java.io.Closeable for information on avoiding resource leaks.
[WARN] android.System: java.lang.Throwable: Explicit termination method 'close' not called
    at dalvik.system.CloseGuard.open(CloseGuard.java)
    at java.io.RandomAccessFile.<init>(RandomAccessFile.java)
    at java.io.RandomAccessFile.<init>(RandomAccessFile.java)
    at java.util.zip.ZipFile.<init>(ZipFile.java)
    at java.util.zip.ZipFile.<init>(ZipFile.java)
    at java.lang.PathClassLoader.init(PathClassLoader.java)
    at java.lang.PathClassLoader.findResource(PathClassLoader.java)
    at java.lang.ClassLoader.getResource(ClassLoader.java)
    at java.lang.Class.getResource(Class.java)
    at com.badlogic.gdx.files.FileHandle.exists(FileHandle.java)
    at com.badlogic.gdx.utils.I18NBundle.loadBundle(I18NBundle.java)
    at com.badlogic.gdx.utils.I18NBundle.loadBundleChain(I18NBundle.java)
    at com.badlogic.gdx.utils.I18NBundle.loadBundleChain(I18NBundle.java)
    at com.badlogic.gdx.utils.I18NBundle.createBundleImpl(I18NBundle.java)
    at com.badlogic.gdx.utils.I18NBundle.createBundle(I18NBundle.java)
    at com.egghead.logic.LogicI18n.<init>(LogicI18n.java)
    at com.egghead.logic.App.createI18n(App.java)
    at com.egghead.core.AppCore.create(AppCore.java)
    at com.egghead.logic.App.create(App.java)
    at com.badlogic.gdx.backends.iosrobovm.IOSGraphics.draw(IOSGraphics.java)
    at com.badlogic.gdx.backends.iosrobovm.IOSGraphics$1.draw(IOSGraphics.java)
    at org.robovm.apple.uikit.UIView.$cb$drawRect$(UIView.java)
    at org.robovm.apple.uikit.UIApplication.main(Native Method)
    at org.robovm.apple.uikit.UIApplication.main(UIApplication.java)
    at com.eggheadgames.quicklogicproblems.IOSLauncher.main(IOSLauncher.java)

Since I don't have an iOS device I can't try if FileHandle#exists() alone triggers this, so I can currently only assure this happens when loading an I18NBundle. Here's some code to replicate:

public class I18NBundleIOSUnclosedResourceTest extends ApplicationAdapter {
    @Override
    public void create() {
        I18NBundle bundle = I18NBundle.createBundle(Gdx.files.internal("i18nStub"));
        Gdx.app.log("key", bundle.get("key"));
        Gdx.app.exit();
    }
}

Put this into your assets folder as i18nStub.properties:

key=value

This should load the bundle, print key: value to the console and exit.

Some more information from @mikemee who tested on an iOS device:

Fwiw, like all good memory bugs, it comes and gos. If I try and strip out everything it goes. If I try to binary-search to see exactly what trips it, then sometimes it will trip and other times it won't - with exactly the same code. However, with most stuff commented out in my IOSLauncher it will still trip, so I'm reasonably confident... I think part of the issue is that it terminates before the message can be emmitted. (As it is, sometimes the value/key message is mixed in with the error message).

I did just switch to my faster device (ipad Mini instead of iPhone 4) and it did occur more frequently, with even more code stripped away. So I agree you should log it. Thanks!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions