2

電話にインストールされているアプリケーションのリストを計算し、アプリケーション名を取得する Android サービスを作成しました。

コードは大まかに次のようになります。

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

私が観察したことは、loadLabelすべてのオブジェクトで関数を呼び出すとpackageInfo、メモリ消費量が大幅に増加することです。私のサービスは通常 3 ~ 5 MB かかり、このコードが実行されると 16 MB に急増します。

ただし、このメモリは最終的に (GC の実行時に) 解放され、サービスは 3 ~ 5 MB に戻ります。このスパイクを回避して目標を達成できるかどうかを知りたいです。

これが欲しい理由は、このアプリを軽量として販売することを計画しているためです。これが続くと不可能です。

4

3 に答える 3

2

私も同じ問題を抱えてる。私のアプリは、通常 32 MB のスパイクを 50 MB に使用します。loadLabel は、サービスから x 秒/分ごとに呼び出される runnable で呼び出されています。私はメモリが90MBまで上がるのを見てきました。私は GC を信頼していますが、私のアプリはデータを記録し、常に実行する必要があるため、OS から終了する可能性が非常に高くなります。

私の解決策は、 ApplicationInfo を null にしてから 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。上記のアプローチでは、情報がロードされた後にそれらへの参照がクリアされますが、アプローチではすべてがリストによって参照されたままになり、ループ全体が終了してpackagesGCできるようになったときにのみGCできます。

私はこのアプリを軽量として販売することを計画していますが、これが続けば不可能です。

ユーザーがメモリ使用量の急増を監視することはないと思います。また、記憶の典型的な認識はちょっと間違っています。空きメモリ=無駄なリソース、持っている場合は携帯電話の速度を上げません。マーケティング!=技術的な詳細:)

于 2012-09-26T12:07:27.533 に答える