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

ApplicationInfo LoadLabel增加我的服务(android)的内存消耗,android,memory-management,Android,Memory Management,我编写了一个android服务,它计算手机上安装的应用程序列表,并获取应用程序名称 代码大致如下所示: List<PackageInfo> appListInfo = pm.getInstalledPackages(0); for (PackageInfo p : appListInfo) { p.applicationInfo.loadLabel(pm).toString());

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

代码大致如下所示:

List<PackageInfo> appListInfo = pm.getInstalledPackages(0);
                for (PackageInfo p : appListInfo) { p.applicationInfo.loadLabel(pm).toString());                                           }       
List appListInfo=pm.getInstalledPackages(0);
对于(PackageInfo p:appListInfo){p.applicationInfo.loadLabel(pm.toString());}
我所观察到的是,当对所有
packageInfo
对象调用
loadLabel
函数时,会大大增加内存消耗。我的服务通常需要3-5MB,执行此代码时会达到16mb

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


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

内存消耗不应该让您担心,因为大峰值并不自动意味着此时无法回收内存。这可能只是意味着垃圾收集是不必要的,因为有足够的可用内存。使用更多的内存甚至可以使事情变得更快,而使用空闲内存没有负面影响

但您可以尝试以下方法以确保对象可以更早地获得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;
List packages=pm.getInstalledPackages(0);
对于(int i=0;i
如果调用
loadLabel
方法后,
PackageInfo
对象保留额外的内存,这可能会有所帮助。在上述方法中,在加载信息后,对这些信息的引用将被清除,而在您的方法中,它们都将被列表引用,并且只有在整个循环完成后才能进行GC,并且可以对包进行GC

我计划以轻量级的方式推广这个应用程序,如果这种情况持续下去,这是不可能的


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

此处的内存消耗不应引起您的关注,因为大峰值并不自动意味着此时无法回收内存。这可能只是意味着垃圾收集是不必要的,因为有足够的可用内存。使用更多的内存甚至可以使事情变得更快,而使用空闲内存没有负面影响

但您可以尝试以下方法以确保对象可以更早地获得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;
List packages=pm.getInstalledPackages(0);
对于(int i=0;i
如果调用
loadLabel
方法后,
PackageInfo
对象保留额外的内存,这可能会有所帮助。在上述方法中,在加载信息后,对这些信息的引用将被清除,而在您的方法中,它们都将被列表引用,并且只有在整个循环完成后才能进行GC,并且可以对包进行GC

我计划以轻量级的方式推广这个应用程序,如果这种情况持续下去,这是不可能的


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

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

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


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

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

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


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

回复永远都不晚

幕后发生的事情是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;
}
。。。
资源和资源;
资产管理人资产管理人;
DisplayMetrics metrics=getDisplayMetricsLocked(null,false);
配置配置=新配置();
列表包=pm.getInstalledPackages(0);
int-tmpResId;
对于(PackageInfo p:软件包){
tmpResId=p.applicationInfo.labelRes;
如果(tmpResId==0){
p、 applicationInfo.setAppName(p.applicationInfo.nonLocalizedLabel);
}否则{
//隐藏的API在这里
assetMgr=新的AssetManager();
if(assetMgr.addAssetPath(p.applicationInfo.sourceDir)==0){
if(assetMgr.addAssetPath(p.applicationInfo.publicSourceDir)==0){
持续
}
}
res=新资源(资产管理组、指标、配置);
//把你的标签拿过来
…res.getText(tmpResId);
res.getAssets().close();