Dalvik ヒープとネイティブヒープを「圧迫」する方法

6,738 views
Skip to first unread message

Kou Sumeragi

unread,
Feb 21, 2012, 3:05:28 AM2/21/12
to android-sdk-japan
先日は質問への回答、ありがとうございました。
早速なのですが、また質問させていただきたく投稿します。

android アプリを開発するにあたって、扱われる Java のヒープは
Dalvik ヒープ と ネイティブヒープ がありますが、製作している
プログラムの負荷テストを行いたいため、これらのメモリを圧迫する
手軽な方法をご存じの方がいらっしゃいましたらお教えいただけ
ませんでしょうか。

Dalvik ヒープはアプリケーション内で
buff = ByteBuffer.allocateDirect(1024*1024*4)
などを繰り返せば圧迫できるようですが、
ネイティブヒープの圧迫が今ひとつ理解しきれていません。
2.1 以前の OS であれば、大きな Bitmap を recycle せずに使い
続ければ圧迫できるようですが、2.2 以降のOSであるため
この方法は使えないようです。

また、Dalvik ヒープはアプリケーションとしての制限である 16MB
以上のメモリを確保できないと認識しておりますが、この制限を
突破してメモリを確保する事は可能でしょうか。

理想としては、独立した一つのアプリケーションとして作成して
目的のアプリケーションに対して外部からメモリ圧迫による
ストレステストを行いたいと考えております。テスト用なので、
ワンボタンで残りメモリの9割くらいを一度に確保して、
可能ならいつでも圧迫したメモリを解放できるような仕様に
なれば理想的です。

皆様のお知恵を拝借させていただきたく。よろしくお願いします。

河村潔広

unread,
Feb 21, 2012, 9:59:45 AM2/21/12
to android-...@googlegroups.com

ヒープが枯渇すると、ヒープを確保したServiceも簡単に殺されるので
Foreground Service としてしておくと、より良いと思います。

米 forground serviceだからといって、殺されないわけではないです

2012/02/21 23:48 "河村潔広" <kyor...@gmail.com>:

河村潔広

unread,
Feb 21, 2012, 9:48:29 AM2/21/12
to android-...@googlegroups.com

16MBの突破するには、AndroidManifestに別プロセスで、
起動するように指定された   Serviceいくつか作成してください

おのおののサービスに16MBヒープをかくほすれば
メモリを圧迫(16*serviceの数だけ)できます

kyorohiro.info

2012/02/21 17:05 "Kou Sumeragi" <kou...@gmail.com>:
--
このメールは Google グループのグループ「Android-SDK-Japan」の登録者に送られています。
このグループに投稿するには、android-...@googlegroups.com にメールを送信してください。
このグループから退会するには、android-sdk-ja...@googlegroups.com にメールを送信してください。
詳細については、http://groups.google.com/group/android-sdk-japan?hl=ja からこのグループにアクセスしてください。

egg

unread,
Feb 21, 2012, 12:02:46 PM2/21/12
to android-...@googlegroups.com
Sumeragiさん

江川と申します。

> buff = ByteBuffer.allocateDirect(1024*1024*4)

これはネイティブヒープになるかと思います。ネイティブヒープにはグローバルリファレンスの話なども絡んできて少々ややこしいので、allocateDirectでもいいんですが、JNI側でmallocするのが最も単純なんじゃないかな、と思います。Dalvik
ヒープについては、new しまくって参照を保持していれば減っていくんじゃないかな、と思います。
 河村さんのおっしゃる方法は、VMのインスタンスを増やしてDalvik側のヒープを増やすことで間接的にネイティブヒープを圧迫する形になるのではないかと想像しています。面白い方法ですね。
 個人的には、自分のアプリのメモリ使用推移が常識的な範囲内に収まっていることを確認できているならそれでいいんじゃないかと思ってしまい、恥ずかしながら負荷テストをやってどのような価値があるか想像できるまでに至っていないのですが、どのような観点でのテストをしたいかによると思いますので、アプリの特性に合わせて適した方法を選ぶのがよいのではないかと思います。

------------------------------------------
EGAWA Takashi

2012年2月21日17:05 Kou Sumeragi <kou...@gmail.com>:

河村潔広

unread,
Feb 21, 2012, 1:17:09 PM2/21/12
to android-...@googlegroups.com
kiyohiroです。

>  河村さんのおっしゃる方法は、VMのインスタンスを増やしてDalvik側のヒープを増やすことで間接的にネイティブヒープを圧迫する形になるのではないかと想像しています。面白い方法ですね。


誤解させてしまいました。
私の説明では、ネイティブヒープについては触れてません。
Dalvikヒープについてだけ触れています。


具体的には、Kou Sumeragi さんの発言した以下の部分について触れています。


>> また、Dalvik ヒープはアプリケーションとしての制限である 16MB
>> 以上のメモリを確保できないと認識しておりますが、この制限を
>> 突破してメモリを確保する事は可能でしょうか。

>> ...
>> ...ワンボタンで残りメモリの9割くらいを一度に確保して、
>> ...
※ プロセスごとに、使用できるヒープは16MB程度 (PFによる)


Kou Sumeragi さんは、以下のような状況を作りたいのではないかと推測しています。
1. Dalvikが使用可能なヒープ全体の90%を使用して、10%としかあいていない
  状態を作る。
2. 1の状態でウニョウニョとテストする。


というわけで、「Serviceごとにプロセスを割り振れば、16MB×プロセス数ぶんだけ
Dalvikのヒープを占有できますよ」ということが言いたい。

うまくすれば、Dalvik全体の90%を使用しているような状況を作れるかもしれません。


そんな感じです。
そろそろ寝ます。


[PS]
具体的にここで、Dalvikヒープとしているのは、
adb shell dumpsys meminfo <Package名>
にて、dalvikの列に表示されるヒープの事とみなして話しています。

この場合、「buff = ByteBuffer.allocateDirect(1024*1024*4)」は
dalvikヒープだったと思います。

河村潔広

unread,
Feb 21, 2012, 1:30:05 PM2/21/12
to android-...@googlegroups.com
kyorohiroです。

> 具体的にここで、Dalvikヒープとしているのは、
> adb shell dumpsys meminfo <Package名>
> にて、dalvikの列に表示されるヒープの事とみなして話しています。
>
> この場合、「buff = ByteBuffer.allocateDirect(1024*1024*4)」は
> dalvikヒープだったと思います。

憶測で発言していました。
dalvikヒープだという根拠がないので、この部分は取り消します。

egg

unread,
Feb 21, 2012, 1:59:14 PM2/21/12
to android-...@googlegroups.com
kyorohiroさんご指摘ありがとうございます。
そうか、そうなんですね、今試してみたらご指摘の通りDalvik ヒープに確保されているように見えました。
allocateDirectはNativeヒープに確保される訳ではなく、Dalvikヒープに確保されるけれども、JNI側から直接参照できるようになるというものなんですね。OpenGLを使う時くらいしか使ったことが無いので、今まで勘違いしていました。
JNI側のCコードでmallocした場合はNative ヒープが減っていくことは確認できました。
ありがとうございました。
------------------------------------------
EGAWA Takashi

2012年2月22日3:30 河村潔広 <kyor...@gmail.com>:

Kou Sumeragi

unread,
Feb 21, 2012, 10:41:56 PM2/21/12
to android-...@googlegroups.com
ご教示いただいた皆様、ありがとうございました。

Service 別スレッドでメモリを確保する方法、および JNI で malloc する方法など
とても参考になりました。

最終的にやりたいのは、Low Memory Killer が発生するような状態を発生させて、
開発中のアプリケーションがどのような挙動をするのかを確認したいのです。
ものすごい極論を言うと、adb などで Low Memory Killer イベントを発生させて
その挙動を確認するという方法でも構わないのですが、その方法が見つかりません
でした。同様に、Low Memory Killer を発生させるようなメモリ圧迫ツールの存在も
探してみましたが見つかりません。(あるのかもしれませんが、non rooted な借用端末
ですので rooted アプリでは無理です)

復習の意味もかねて、現時点での理解とやりたい事、作るべき物をまとめてみます。

android で扱うメモリには大きくわけて2種類があり、

1)Linux ヒープ
 搭載されている物理的なRAMの全領域を扱って、android OS 全体に使われる。
 OS やカーネルに割り当てられるメモリの他に、以下のアプリケーションヒープも含まれる。

2)アプリケーションヒープ
 各アプリケーション毎に OS によって割り当てられるメモリ領域で、多くの機種で
 デフォルトで 16MB ほど。JDK で作られたアプリケーションはこのメモリを使う。
 このヒープも大きく分けて2種類に分類される。

2-A) Dalvik (Java) ヒープ
 Dalvik (Java) が使う変数などを配置するメモリ。
2-B)ネイティブヒープ
 Bitmap などのリソースで扱うメモリ。

メモリエラーの種類
 1)のメモリが不足すると、Low Memory Killer が自動で発動し、現在実行されている
 アプリが自動的に KILL される(ものがある)

 この2-A)、2-B) の合計が16MBを超すると、Out Of Memory エラーが発生する。

提案された方法の解釈
・JNI で malloc する方法
 JNI の中で malloc する事で直接 1)のメモリを圧迫するため、Low Memory Killer を
 呼び出せる?それとも JNI で malloc をかけても圧迫されるメモリは 2-B)のメモリ
 なので Out Of Memory エラーが発生する?

・別スレッド Service を16MBづつメモリ確保して複数起動する。
 2)のメモリをどんどん確保する事で間接的に 1)のメモリを圧迫するため
 Low Memory Killer を呼び出せる?

申し訳ありません、このへんがまだ十分に理解できておりません。また、

1つのアプリケーションヒープの領域を他のアプリケーションから圧迫する事はできるのか、
などの android のメモリ管理に関する基本的な知識が欠如している事は自覚しており
ます。「このへん読んどけ」みたいなドキュメントがありましたらポインタでもいいので
お教えいただけませんでしょうか。

長々とした返信になりましたが、よろしくお願いします。

2012年2月22日3:59 egg <t.e...@gmail.com>:

河村潔広

unread,
Feb 22, 2012, 10:10:23 AM2/22/12
to android-...@googlegroups.com

> 別スレッド Service を16MBづつメモリ確保して複数起動する。 2)のメモリをどんどん確保する事で間接的に 1)のメモリを圧迫するため Low Memory Killer を呼び出せる?

念のため、別スレットでもまちがいないですが
別プロセスである必要があります。

Low Memory Killerは発生します
米 少なくとも以前私が試した端末ではおこせたので...、断言するほど自信はありませんが...

そんな感じです

2012/02/22 12:43 "Kou Sumeragi" <kou...@gmail.com>:

河村潔広

unread,
Feb 22, 2012, 10:20:55 AM2/22/12
to android-...@googlegroups.com

kyorohiroです

> ます。「このへん読んどけ」みたいなドキュメントがありましたらポインタでも いいので お教えいただけませんでしょうか。

レスしている文面から、Low Memory Killerにかんする
情報源には差がないようないがしました。

なので、特別これを読め的なものはないです。

時間に余裕あるならば、該当するandroidコードを読むと良いと思います。

解説できるほど詳しくも無いので、こんな感じで...
おそまつさまです。

2012/02/22 12:43 "Kou Sumeragi" <kou...@gmail.com>:
ご教示いただいた皆様、ありがとうございました。

kyorohiro

unread,
Mar 10, 2012, 11:32:27 AM3/10/12
to Android-SDK-Japan
kyorohiroです。

>
> 16MBの突破するには、AndroidManifestに別プロセスで、
> 起動するように指定された Serviceいくつか作成してください
> おのおののサービスに16MBヒープをかくほすれば
> メモリを圧迫(16*serviceの数だけ)できます
>

kyorohiroが紹介したことを実現したコードを下記におきました。
* https://github.com/kyorohiro/KyoroHelloAndroid
./KyoroStress


* Androidマーケットにも展開してみました。
https://play.google.com/store/apps/details?id=info.kyorohiro.helloworld.stress&feature=search_result#?t=W251bGwsMSwxLDEsImluZm8ua3lvcm9oaXJvLmhlbGxvd29ybGQuc3RyZXNzIl0.


* android group japanで、Low Memory Killerで困っている人に使ってもらえました。
http://groups.google.com/group/android-group-japan/browse_frm/thread/cd50cc07474404d2


ニッチなアプリなので、使う人はほとんどいないと思いますが...
皆さんのお役に立てれば幸いです。

そんな感じで!!
> 2012/02/21 23:48 "河村潔広" <kyoroh...@gmail.com>:

河村潔広

unread,
Feb 17, 2013, 9:17:39 AM2/17/13
to Android-SDK-Japan
kyorohiroです。

KyoroStressは、最近の端末でうまく動作しないみたいです。 端末の機能が良くなったのが理由です。

そこで、最新の端末でもLow Memory Killerが頻繁に発生する状況を作ることができるように、KyoroStressを作り直しました。

以下の場所に置きました。

[ソースとAPK]
https://github.com/kyorohiro/KyoroStressV2

[使い方/仕組み]
http://kyorohiro.blogspot.jp/2013/02/kyorostress-1-low-memory-killer.html


使う人はほとんどいないと思いますが、皆様のお役に立てれば幸いです。


以上です。

2012年3月11日 1:32 kyorohiro <kyor...@gmail.com>:
Reply all
Reply to author
Forward
0 new messages