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



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

代码大致如下:

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

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

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

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

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

我的解决方案是使ApplicationInfo为null,然后调用System.gc()来释放内存。这样,我的应用程序保持在32兆字节。

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

回复永远不会太迟

幕后发生的事情是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;
}

内存消耗不应与您有关,因为大峰值并不意味着此时无法回收内存。这可能只是意味着垃圾回收没有必要,因为有足够的可用内存。使用更多的内存甚至可以让事情更快,使用空闲内存没有负面副作用。

但是您可以尝试以下操作来确保对象可以更早地获得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;

如果调用loadLabel方法后PackageInfo对象保留了额外的内存,这可能会有所帮助。在上面的方法中,对这些的引用在信息加载后被清除,而在您的方法中它们都保持由列表引用,并且只有在整个循环完成后才能被GC'd,并且packages可以被GC'd。

我计划将这款应用程序作为轻量级应用程序进行营销,如果这种情况持续下去,这是不可能的。

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

最新更新