在阿帕奇和谐的JarURLConnectionImpl Android的内存泄漏?阿帕奇、内存、和谐、JarURLConnectionImpl

2023-09-06 13:45:03 作者:携剑笑红尘

我工作的一个Android应用程序,我们正在调查的内存使用。

I'm working on an Android app and we're investigating memory use.

看着从HPROF堆转储,我们看到近2M(我们堆的22%)在JarURLConnectionImpl静态缓存被使用:

Looking at a heap dump from hprof, we're seeing nearly 2M (22% of our heap) being used in a static cache in JarURLConnectionImpl:

纵观source code代表JarURLConnectionImpl 的,看来条目被添加到静态jarCache变量,但永远不会被删除。

Looking at the source code for JarURLConnectionImpl, it appears that entries are added to the static jarCache variable, but never removed.

如果这是真的,他们永远不会被删除,这让我觉得作为一个潜在的内存泄漏。

If it's true that they're never removed, that strikes me as a potential memory leak.

这是泄漏?是否有修补程序或解决方法吗?

Is this a leak? Is there a fix or workaround?

推荐答案

下面是一个丑陋的解决方法:

Here's an ugly workaround:

private static HashMap<URL,JarFile> jarCache;


static {
    try {
        Class<?> jarURLConnectionImplClass = Class.forName("org.apache.harmony.luni.internal.net.www.protocol.jar.JarURLConnectionImpl");
        final Field jarCacheField = jarURLConnectionImplClass.getDeclaredField("jarCache");
        jarCacheField.setAccessible(true);
        //noinspection unchecked
        jarCache = (HashMap<URL, JarFile>) jarCacheField.get(null);
    } catch(Exception e) {
        // ignored
    }
}

然后,定期运行以下命令:

Then, periodically run the following:

    // HACK http://stackoverflow.com/questions/14610350/android-memory-leak-in-apache-harmonys-jarurlconnectionimpl
    if( jarCache!=null ) {
        try {
            for (
                final Iterator<Map.Entry<URL, JarFile>> iterator = jarCache.entrySet().iterator(); iterator.hasNext(); ) {
                final Map.Entry<URL, JarFile> e = iterator.next();
                final URL url = e.getKey();
                if (Strings.toString(url).endsWith(".apk")) {
                    Log.i(TAG,"Removing static hashmap entry for " + url);
                    try {
                        final JarFile jarFile = e.getValue();
                        jarFile.close();
                        iterator.remove();
                    } catch( Exception f ) {
                        Log.e(TAG,"Error removing hashmap entry for "+ url,f);
                    }
                }
            }
        } catch( Exception e ) {
            // ignored
        }
    }

我运行它的活动创造所以它会被执行每次创建我的活动一次。丑陋的HashMap的入口似乎并没有得到重新创建所有的时候,但它似乎重新出现偶尔,所以它是不够的只是运行此code一次。

I run it on activity creation so it gets executed every time one of my activities is created. The ugly hashmap entry doesn't seem to get recreated all that often, but it DOES seem to reappear occasionally, so it's not sufficient to just run this code once.