ApplicationInfo LoadLabel增加我服务的内存消耗(android)

时间:2012-09-26 11:43:18

标签: android memory-management

我写了一个android服务,它计算手机上安装的应用程序列表并获取应用程序名称。

代码大致如下:

List<PackageInfo> appListInfo = pm.getInstalledPackages(0);
                for (PackageInfo p : appListInfo) { p.applicationInfo.loadLabel(pm).toString());                                           }       

我所观察到的是,loadLabel函数在所有packageInfo对象上调用时会大大增加内存消耗。我的服务通常需要3-5 MB,并且在执行此代码时会增加到16mb。

虽然,这个记忆最终会被释放(当GC运行时)并且服务回到3-5mb,我想知道这个尖峰是否可以避免并且仍能实现我的目标

我想要的原因是,我打算将这个应用程序推向轻量级,如果这种情况不断发生,这是不可能的。

3 个答案:

答案 0 :(得分:1)

我有同样的问题。我的应用程序,通常使用32mb尖峰到50mb。 loadLabel在runnable中被调用,每隔x秒/分钟从服务调用一次。我已经看到内存高达90mb。我相信GC,但我的应用程序记录数据并且需要一直运行,因此它非常有资格从操作系统终止。

我的解决方案是将ApplicationInfo置空,然后调用System.gc()来释放内存。这样我的应用程序保持在32mb。

如果有人有更好的方法,请通知我们。

答案 1 :(得分:1)

回复

永远不会太迟

幕后发生的事情是android加载每个应用程序apk,因此它是资源,以便从资源中获取文本。

虽然在GC发生之前资源不会被关闭,但是只有在您担心增加尺寸时才会有一些成本。

您可以使用隐藏的API并自行加载资源,并在完成后将其删除。

...
Resources res;
AssetManager assetMgr;  
DisplayMetrics metrics = getDisplayMetricsLocked(null, false);
Configuration config = new Configuration();
List<PackageInfo> packages = pm.getInstalledPackages(0);
int tmpResId;
for (PackageInfo p: packages){
     tmpResId = p.applicationInfo.labelRes;
     if(tmpResId == 0){
         p.applicationInfo.setAppName(p.applicationInfo.nonLocalizedLabel);
     }else {
        //hidden API's here
        assetMgr = new AssetManager();
        if(assetMgr.addAssetPath(p.applicationInfo.sourceDir) == 0){
        if(assetMgr.addAssetPath(p.applicationInfo.publicSourceDir) == 0){
           continue;
        }
        }
        res = new Resources(assetMgr, metrics, config);
        //Get your label here
        ...res.getText(tmpResId);
        res.getAssets().close();
    }

}
assetMgr = null;
res = null;
...

static DisplayMetrics getDisplayMetricsLocked(CompatibilityInfo ci, boolean  forceUpdate) {
    DisplayMetrics dm = new DisplayMetrics();
    Display d = WindowManagerImpl.getDefault(ci).getDefaultDisplay();
    d.getMetrics(dm);
    return dm;
}

答案 2 :(得分:0)

此处的内存消耗不应该与您有关,因为大峰值并不会自动意味着当时无法回收内存。它可能只是意味着没有必要进行垃圾收集,因为有足够的可用内存。使用更多内存甚至可以使事情更快,使用可用内存没有负面的副作用。

但是你可以尝试以下方法来确保对象之前可以获得GC:

List<PackageInfo> packages = pm.getInstalledPackages(0);
for (int i = 0; i < packages.size(); i++) {
    PackageInfo p = packages.set(i, null);
    p.applicationInfo.loadLabel(pm).toString();
}
packages = null;

一旦调用PackageInfo方法,loadLabel对象保留额外内存,这可能会有所帮助。使用上述方法,在加载信息后清除对它们的引用,而在您的方法中它们仍然被列表引用,并且只有在整个循环结束并且packages可以是GC后才能进行GC。

  

我打算将此应用推向轻量级,如果这种情况不断发生,这是不可能的。

我怀疑用户是否会监控尖峰的内存使用情况。对记忆的典型看法也是错误的。可用内存=浪费资源,如果你拥有它,不会加速你的手机。营销!=技术细节:)