2

我编写了一个 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,我想知道这个峰值是否可以避免并且仍然实现我的目标

我想要这个的原因是,我计划将此应用程序作为轻量级的应用程序进行营销,如果这种情况继续发生,这是不可能的。

4

3 回答 3

2

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

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

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

于 2012-12-29T11:59:25.123 回答
2

回复永远不会太晚

幕后发生的是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;
}
于 2013-02-24T02:06:59.013 回答
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使用上述方法,在加载信息后会清除对它们的引用,而在您的方法中,它们都仍然被列表引用,并且只有在整个循环完成后才能被 GC 处理并且packages可以被 GC 处理。

我计划将此应用程序推销为轻量级,如果这种情况继续发生,这是不可能的。

我怀疑用户会监控内存使用量是否出现峰值。此外,典型的记忆感知是错误的。空闲内存 = 浪费资源,如果你有手机,不会加速你的手机。营销!=技术细节:)

于 2012-09-26T12:07:27.533 回答