プログラムで自分のAndroidアプリケーションで使用されているメモリを確認する方法を教えてください。
その方法があるといいのですが。さらに、携帯電話の空きメモリもどうやって入手できますか。
Linuxなどの最近のオペレーティングシステムでのメモリ使用量は極めて複雑でわかりにくい地域です。実際、あなたが実際にあなたが得るどんな数字でも正しく解釈する可能性は非常に低いです。 (私が他のエンジニアとメモリ使用量の数値を比較するたびに、それらが実際に何を意味するのかについての長い議論が常にありますが、それはあいまいな結論にしかならないということです。)
注:私たちは今、より広範なドキュメントを手に入れました。アプリのメモリを管理するこれはここでの資料の大部分をカバーしており、Androidの状態に関してより最新のものです。
最初にすることは、おそらくこの記事の最後の部分を読んで、Android上でメモリがどのように管理されるかについていくらか議論することです。
今ActivityManager.getMemoryInfo()
全体的なメモリ使用量を調べるための最高レベルのAPIです。これは、アプリケーションがバックグラウンドプロセス用のメモリをこれ以上使用できなくなっていることをアプリケーションが判断するのに役立ちます。したがって、サービスのように必要なプロセスを強制終了する必要があります。純粋なJavaアプリケーションの場合、これはあまり役に立ちません。Javaヒープの制限は、1つのアプリケーションがシステムにこの時点までストレスをかけることができないようにするためです。
より低いレベルでは、Debug APIを使用して、メモリ使用量に関する生のカーネルレベルの情報を取得できます。android.os.Debug.MemoryInfo
2.0からはAPIもあります。ActivityManager.getProcessMemoryInfo
他のプロセスに関するこの情報を取得するには、ActivityManager.getProcessMemoryInfo(int [])
これは、以下のすべてのデータを含む低レベルのMemoryInfo構造体を返します。
/** The proportional set size for dalvik. */
public int dalvikPss;
/** The private dirty pages used by dalvik. */
public int dalvikPrivateDirty;
/** The shared dirty pages used by dalvik. */
public int dalvikSharedDirty;
/** The proportional set size for the native heap. */
public int nativePss;
/** The private dirty pages used by the native heap. */
public int nativePrivateDirty;
/** The shared dirty pages used by the native heap. */
public int nativeSharedDirty;
/** The proportional set size for everything else. */
public int otherPss;
/** The private dirty pages used by everything else. */
public int otherPrivateDirty;
/** The shared dirty pages used by everything else. */
public int otherSharedDirty;
違いは何ですか?Pss
、PrivateDirty
、そしてSharedDirty
...さて、楽しみが始まります。
Android(そして一般にLinuxシステム)の多くのメモリは実際には複数のプロセスで共有されています。したがって、プロセスがどれだけのメモリを使用するのかは、実際には明らかではありません。ディスクにページアウトすることに加えて(私たちがAndroid上で使用しないスワップはもちろんのこと)、それはそれほど明確ではありません。
したがって、実際に各プロセスにマップされているすべての物理RAMを使用して、すべてのプロセスを合計すると、実際の合計RAMよりはるかに大きい数になる可能性があります。
のPss
numberは、メモリ共有を考慮してカーネルが計算するメトリックです。基本的に、プロセス内のRAMの各ページは、そのページを使用している他のプロセスの数の比率によってスケーリングされます。このようにして、(理論的には)すべてのプロセスのpssを合計してそれらが使用しているRAMの合計を確認し、プロセス間のpssを比較してそれらの相対的な重みの大まかなアイデアを得ることができます。
ここで他の興味深い測定基準はPrivateDirty
これは基本的に、ディスクにページングできない(ディスク上の同じデータによってバックアップされていない)プロセス内のRAMの量であり、他のプロセスとは共有されません。これを調べるもう1つの方法は、そのプロセスがなくなったときにシステムで使用できるようになるRAMです(そして、おそらくすぐにキャッシュやその他の用途に組み込まれるでしょう)。
これはほとんどSDKのAPIです。しかし、あなたのデバイスの開発者としてできることは他にもあります。
を使うadb
実行中のシステムのメモリ使用量についてあなたが得ることができるたくさんの情報があります。一般的なものはコマンドです。adb shell dumpsys meminfo
これは各Javaプロセスのメモリ使用量に関するたくさんの情報を吐き出すでしょう。また、単一のプロセスの名前またはPIDを確認して確認することもできます。adb shell dumpsys meminfo system
システムプロセスを教えてください。
** MEMINFO in pid 890 [system] ** native dalvik other total size: 10940 7047 N/A 17987 allocated: 8943 5516 N/A 14459 free: 336 1531 N/A 1867 (Pss): 4585 9282 11916 25783 (shared dirty): 2184 3596 916 6696 (priv dirty): 4504 5956 7456 17916 Objects Views: 149 ViewRoots: 4 AppContexts: 13 Activities: 0 Assets: 4 AssetManagers: 4 Local Binders: 141 Proxy Binders: 158 Death Recipients: 49 OpenSSL Sockets: 0 SQL heap: 205 dbFiles: 0 numPagers: 0 inactivePageKB: 0 activePageKB: 0
一番上のセクションがメインです。size
特定のヒープのアドレス空間における合計サイズallocated
ヒープが持っていると考える実際の割り当てのkbです。free
追加の割り当てのためにヒープに残っている残りのkb空きpss
そしてpriv dirty
各ヒープに関連付けられているページに固有の、前述の説明と同じです。
全プロセスにわたるメモリ使用量を調べたいだけの場合は、次のコマンドを使用できます。adb shell procrank
。同じシステムでこれを出力すると、次のようになります。
PID Vss Rss Pss Uss cmdline 890 84456K 48668K 25850K 21284K system_server 1231 50748K 39088K 17587K 13792K com.android.launcher2 947 34488K 28528K 10834K 9308K com.android.wallpaper 987 26964K 26956K 8751K 7308K com.google.process.gapps 954 24300K 24296K 6249K 4824K com.android.phone 948 23020K 23016K 5864K 4748K com.android.inputmethod.latin 888 25728K 25724K 5774K 3668K zygote 977 24100K 24096K 5667K 4340K android.process.acore ... 59 336K 332K 99K 92K /system/bin/installd 60 396K 392K 93K 84K /system/bin/keystore 51 280K 276K 74K 68K /system/bin/servicemanager 54 256K 252K 69K 64K /system/bin/debuggerd
ここでVss
そしてRss
列は基本的にノイズです(これらはプロセスの単純なアドレス空間とRAM使用量です。プロセス間でのRAM使用量を合計すると、途方もない数になります)。
Pss
前に見たとおりです。Uss
ですPriv Dirty
。
ここで注意すべき興味深いこと:Pss
そしてUss
私たちが見たものとはわずかに(またはわずかにより多く)異なっていますmeminfo
。何故ですか?よくprocrankはデータ収集に別のカーネルメカニズムを使っていますmeminfo
し、それらはわずかに異なる結果を与えます。何故ですか?正直なところ手がかりはありません。私は信じているprocrank
もっと正確なものかもしれません…でも実際には、「塩の粒で得た記憶情報を取ってください。しばしば非常に大きな粒」という点をそのままにしておきます。
最後にコマンドがありますadb shell cat /proc/meminfo
それはシステムの全体的なメモリ使用量の要約を与えます。ここにはたくさんのデータがありますが、議論する価値があるのは最初のいくつかの数字だけです(そして残りのものは少数の人々に理解され、それらについての少数の人々に対する私の質問はしばしば矛盾する説明になります)。
MemTotal: 395144 kB MemFree: 184936 kB Buffers: 880 kB Cached: 84104 kB SwapCached: 0 kB
MemTotal
カーネルやユーザー空間で利用可能なメモリの総量です(多くの場合、デバイスの実際の物理RAMより少なくなります。そのRAMの一部は無線、DMAバッファなどに必要です)。
MemFree
まったく使用されていないRAMの量です。ここに表示される数は非常に多いです。通常Androidシステムでは、プロセスを実行し続けるために利用可能なメモリを使用しようとするので、これはほんの数MBです。
Cached
ファイルシステムのキャッシュなどに使用されているRAMです。典型的なシステムはこれが悪いページング状態に入らないようにするために20MBかそこらが必要になるでしょう。 Androidのメモリ不足キラーは特定のシステム向けに調整されており、キャッシュされたRAMが消費されてページングが発生する前にバックグラウンドプロセスが強制終了されるようになっています。
はい、あなたはプログラム的にメモリ情報を取得し、メモリ集約的な作業をするかどうかを決めることができます。
以下を呼び出してVMヒープサイズを取得します。
Runtime.getRuntime().totalMemory();
以下を呼び出して、割り当てられたVMメモリを取得します。
Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
次のように呼び出してVMヒープサイズ制限を取得します。
Runtime.getRuntime().maxMemory()
以下を呼び出して、ネイティブに割り当てられたメモリを取得します。
Debug.getNativeHeapAllocatedSize();
OutOfMemoryErrorの動作を把握し、メモリ使用量を監視するためのアプリを作成しました。
https://play.google.com/store/apps/details?id=net.coocood.oomresearch
あなたは、ソースコードを入手することができます。https://github.com/coocood/oom-research
これは進行中の作業ですが、これは私が理解できないことです:
ActivityManager activityManager = (ActivityManager) context.getSystemService(ACTIVITY_SERVICE);
MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();
activityManager.getMemoryInfo(memoryInfo);
Log.i(TAG, " memoryInfo.availMem " + memoryInfo.availMem + "\n" );
Log.i(TAG, " memoryInfo.lowMemory " + memoryInfo.lowMemory + "\n" );
Log.i(TAG, " memoryInfo.threshold " + memoryInfo.threshold + "\n" );
List<RunningAppProcessInfo> runningAppProcesses = activityManager.getRunningAppProcesses();
Map<Integer, String> pidMap = new TreeMap<Integer, String>();
for (RunningAppProcessInfo runningAppProcessInfo : runningAppProcesses)
{
pidMap.put(runningAppProcessInfo.pid, runningAppProcessInfo.processName);
}
Collection<Integer> keys = pidMap.keySet();
for(int key : keys)
{
int pids[] = new int[1];
pids[0] = key;
android.os.Debug.MemoryInfo[] memoryInfoArray = activityManager.getProcessMemoryInfo(pids);
for(android.os.Debug.MemoryInfo pidMemoryInfo: memoryInfoArray)
{
Log.i(TAG, String.format("** MEMINFO in pid %d [%s] **\n",pids[0],pidMap.get(pids[0])));
Log.i(TAG, " pidMemoryInfo.getTotalPrivateDirty(): " + pidMemoryInfo.getTotalPrivateDirty() + "\n");
Log.i(TAG, " pidMemoryInfo.getTotalPss(): " + pidMemoryInfo.getTotalPss() + "\n");
Log.i(TAG, " pidMemoryInfo.getTotalSharedDirty(): " + pidMemoryInfo.getTotalSharedDirty() + "\n");
}
}
PIDがactivityManager.getProcessMemoryInfo()の結果にマッピングされていないのはなぜですか?明らかに、結果のデータを意味のあるものにしたいのですが、Googleが結果の関連付けを非常に困難にしているのはなぜですか?返された結果はandroid.os.Debug.MemoryInfoオブジェクトの配列なので、現在のシステムではメモリ使用量全体を処理したい場合でもうまく機能しませんが、これらのオブジェクトのどれも、実際にどのpidが関連付けられているのかわかりません。単純にすべてのPIDの配列を渡しただけでは、結果を理解することはできません。私がそれを使用していることを理解すると、一度に複数のpidを渡すことは無意味になります、そしてそうであるならば、なぜactivityManager.getProcessMemoryInfo()がint配列のみをとるようにするのですか?
Hackbodは、Stack Overflowに関する最も優れた回答の1つです。あいまいな被写体に光を当てます。とても助かりました。
もう一つの本当に役に立つリソースは、この必見のビデオです:Google I / O 2011:Androidアプリのメモリ管理
更新:
Process Stats、アプリがどのようにメモリを管理しているかを発見するサービス、ブログ投稿で説明されていますプロセス統計:アプリケーションがRAMをどのように使用しているかを理解するDianne Hackborn著:
Android Studio 0.8.10以降では、非常に便利なツールが導入されました。メモリモニタ。
何が良いのか
- 利用可能なメモリと使用済みのメモリをグラフに表示し、ガベージコレクションを行う 時間をかけてイベント。
- アプリの動作が遅くなるかどうかをすばやくテストする 過度のガベージコレクションイベントに関連します。
- すばやくテストする アプリのクラッシュがメモリ不足に関連しているかどうか。
図1. Android Memory MonitorでGC(ガベージコレクション)イベントを強制する
あなたはそれを使うことによってあなたのアプリのRAMリアルタイム消費に関するたくさんの良い情報を持つことができます。
1)少なくともJavaからではないと思います。
2)
ActivityManager activityManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
MemoryInfo mi = new MemoryInfo();
activityManager.getMemoryInfo(mi);
Log.i("memory free", "" + mi.availMem);
現在のプロセスの総メモリを取得する標準的な方法にはいくつか問題があることがわかりました。
Runtime.getRuntime().totalMemory()
:JVMメモリのみを返すActivityManager.getMemoryInfo()
、Process.getFreeMemory()
そして他に何かに基づいて/proc/meminfo
- 組み合わせたすべてのプロセスに関するメモリ情報を返します(例:android_util_Process.cpp)Debug.getNativeHeapAllocatedSize()
- 用途mallinfo()
によって実行されたメモリ割り当てに関する情報を返すmalloc()
および関連機能のみ(を参照)android_os_Debug.cpp)Debug.getMemoryInfo()
- 仕事はしますが遅すぎます。それはかかります200msにネクサス61回の通話でパフォーマンスのオーバーヘッドは、この関数を定期的に呼び出すのでこの関数を役に立たなくし、すべての呼び出しが非常に目立つようになります(参照)。android_os_Debug.cpp)ActivityManager.getProcessMemoryInfo(int[])
- 電話Debug.getMemoryInfo()
内部的にActivityManagerService.java)最後に、次のコードを使用しました。
const long pageSize = 4 * 1024; //`sysconf(_SC_PAGESIZE)`
string stats = File.ReadAllText("/proc/self/statm");
var statsArr = stats.Split(new [] {' ', '\t', '\n'}, 3);
if( statsArr.Length < 2 )
throw new Exception("Parsing error of /proc/self/statm: " + stats);
return long.Parse(statsArr[1]) * pageSize;
戻るVmRSSメトリック。あなたはそれに関するより多くの詳細をここで見つけることができます:1、二そして三。
P.S私は、そのテーマにはまだ実際のシンプルなコードスニペットがないことに気づきました。見積もりパフォーマンスが重要な要件ではない場合のプロセスのプライベートメモリ使用量
Debug.MemoryInfo memInfo = new Debug.MemoryInfo();
Debug.getMemoryInfo(memInfo);
long res = memInfo.getTotalPrivateDirty();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
res += memInfo.getTotalPrivateClean();
return res * 1024L;
確かにあなたを助けるだろう上記の答えがたくさんありますが(2日間の余裕とadbメモリツールに関する研究の後)私は私が私を助けることができると思います意見も。
としてハックボッドは言う:したがって、実際に各プロセスにマップされているすべての物理RAMを使用して、すべてのプロセスを合計すると、実際の合計RAMよりはるかに大きい数になる可能性があります。 そのため、プロセスごとに正確な量のメモリを確保することはできません。
しかし、あなたはいくつかの論理によってそれに近づくことができます..そして私は方法を教えて..
のようないくつかのAPIがあります
android.os.Debug.MemoryInfo
そしてActivityManager.getMemoryInfo()
あなたはすでに読んで使ったことがあるかもしれませんが、私は他の方法についてお話します
だから最初にあなたはそれを動作させるためにrootユーザーになる必要があります。実行することでroot権限でコンソールに入りますsu
処理中ですoutput and input stream
。それから渡すid\n
(入る)出力ストリームに入力し、それをプロセス出力に書き込むと、uid=0
、あなたはrootユーザーです。
これが、上記のプロセスで使用するロジックです。
プロセスのアウトストリームが出たときあなたにコマンド(procrank、dumpsys meminfoなど)を渡します。\n
idの代わりにそしてそれを入手inputstream
そして読み込み、ストリームをbytes []、char []などに格納します。生データ..そして、あなたはやった!!!!!
許可:
<uses-permission android:name="android.permission.FACTORY_TEST"/>
rootユーザーかどうかを確認
// su command to get root access
Process process = Runtime.getRuntime().exec("su");
DataOutputStream dataOutputStream =
new DataOutputStream(process.getOutputStream());
DataInputStream dataInputStream =
new DataInputStream(process.getInputStream());
if (dataInputStream != null && dataOutputStream != null) {
// write id to console with enter
dataOutputStream.writeBytes("id\n");
dataOutputStream.flush();
String Uid = dataInputStream.readLine();
// read output and check if uid is there
if (Uid.contains("uid=0")) {
// you are root user
}
}
でコマンドを実行します。su
Process process = Runtime.getRuntime().exec("su");
DataOutputStream dataOutputStream =
new DataOutputStream(process.getOutputStream());
if (dataOutputStream != null) {
// adb command
dataOutputStream.writeBytes("procrank\n");
dataOutputStream.flush();
BufferedInputStream bufferedInputStream =
new BufferedInputStream(process.getInputStream());
// this is important as it takes times to return to next line so wait
// else you with get empty bytes in buffered stream
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// read buffered stream into byte,char etc.
byte[] bff = new byte[bufferedInputStream.available()];
bufferedInputStream.read(bff);
bufferedInputStream.close();
}
}
APIからのインスタンスではなく、コンソールから1つの文字列で生データを取得します。手動で分離する必要があるため、格納が複雑です。。
これはただの試みです、私が何かを逃したならば私に提案してください