【问题标题】:ApplicationInfo LoadLabel increase memory consumption of my service (android)ApplicationInfo LoadLabel 增加我的服务的内存消耗(android)
【发布时间】:2012-09-26 11:43:18
【问题描述】:

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

代码大致如下:

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

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

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

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

【问题讨论】:

    标签: android memory-management


    【解决方案1】:

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

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

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

    【讨论】:

      【解决方案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;
      }
      

      【讨论】:

        【解决方案3】:

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

        但是您可以尝试以下方法来确保对象可以更早地被 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 和 packages 可以被 GC。

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

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

        【讨论】:

          猜你喜欢
          • 2010-09-06
          • 1970-01-01
          • 1970-01-01
          • 2019-10-31
          • 2021-03-10
          • 1970-01-01
          • 1970-01-01
          • 2012-04-09
          • 1970-01-01
          相关资源
          最近更新 更多