ph4*_*r05 18 android garbage-collection memory-leaks classloader native-code
我在我的Android应用程序中使用了一些本机库,我想在某个时间点将它们从内存中卸载.当加载了加载本机库的类的ClassLoader被垃圾收集时,库将被卸载.灵感:原生卸货.
在下面的代码中,我通过省略本机库加载代码来简化案例,只演示了Classloader内存泄漏.
我在Android KitKat 4.4.2,API 19上测试了它.设备:Motorola Moto G.
为了演示,我有以下ClassLoader,派生自PathClassLoader用于加载Android应用程序.
package com.demo;
import android.util.Log;
import dalvik.system.PathClassLoader;
public class LibClassLoader extends PathClassLoader {
private static final String THIS_FILE="LibClassLoader";
public LibClassLoader(String dexPath, String libraryPath, ClassLoader parent) {
super(dexPath, libraryPath, parent);
}
@Override
protected void finalize() throws Throwable {
Log.v(THIS_FILE, "Finalizing classloader " + this);
super.finalize();
}
}
Run Code Online (Sandbox Code Playgroud)
我有EmptyClass加载LibClassLoader.
package com.demo;
public class EmptyClass {
}
Run Code Online (Sandbox Code Playgroud)
内存泄漏是由以下代码引起的:
final Context ctxt = this.getApplicationContext();
PackageInfo pinfo = ctxt.getPackageManager().getPackageInfo(ctxt.getPackageName(), 0);
LibClassLoader cl2 = new LibClassLoader(
pinfo.applicationInfo.publicSourceDir,
pinfo.applicationInfo.nativeLibraryDir,
ClassLoader.getSystemClassLoader()); // Important: parent cannot load EmptyClass.
if (memoryLeak){
Class<?> eCls = cl2.loadClass(EmptyClass.class.getName());
Log.v("Demo", "EmptyClass loaded: " + eCls);
eCls=null;
}
cl2=null;
// Try to invoke GC
System.runFinalization();
System.gc();
Thread.sleep(250);
System.runFinalization();
System.gc();
Thread.sleep(500);
System.runFinalization();
System.gc();
Debug.dumpHprofData("/mnt/sdcard/hprof"); // Dump heap, hardcoded path...
Run Code Online (Sandbox Code Playgroud)
需要注意的重要一点是,cl2不是父ctxt.getClassLoader()类,是加载演示代码类的类加载器.这是设计原因,因为我们不想cl2使用它的父加载EmptyClass.
问题是,如果memoryLeak==false,然后cl2收集垃圾.如果memoryLeak==true出现内存泄漏.此行为与标准JVM上的观察结果不一致(我使用[ 1 ]中的类加载器来模拟相同的行为).在两种情况下,JVM cl2都会收集垃圾.
我还用Eclipse MAT分析了堆转储文件,cl2并没有进行垃圾收集,因为类EmptyClass仍然保留了对它的引用(因为类在它们的类加载器上保存引用).这是有道理的.但EmptyClass显然不是没有理由收集的垃圾.GC root的路径就是这样EmptyClass.我没有设法说服GC完成任务EmptyClass.
对于HEAPDUMP文件memoryLeak==true可以发现在这里,Eclipse的Android项目与此内存泄漏的演示应用在这里.
我还尝试了加载EmptyClassin的另一种变体LibClassLoader,即Class.forName(...)或cl2.findClass().使用/不使用静态初始化时,结果始终相同.
我查了很多在线资源,据我所知,没有涉及静态缓存领域.我检查了PathClassLoader它和它的父类的源代码,我发现没有问题.
我非常感谢您的见解和任何帮助.
System.gc()只是为JVM/Dalvik执行GC的提示.我只是想知道为什么会有内存泄漏.为了让Erik Hellman写的更清楚,我说的是加载NDK编译的C/C++库,动态链接,后缀为.so.
| 归档时间: |
|
| 查看次数: |
1183 次 |
| 最近记录: |