我写了一个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,我想知道这个尖峰是否可以避免并且仍能实现我的目标
我想要的原因是,我打算将这个应用程序推向轻量级,如果这种情况不断发生,这是不可能的。
答案 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。
我打算将此应用推向轻量级,如果这种情况不断发生,这是不可能的。
我怀疑用户是否会监控尖峰的内存使用情况。对记忆的典型看法也是错误的。可用内存=浪费资源,如果你拥有它,不会加速你的手机。营销!=技术细节:)