このページではAndroidアプリ開発関連のメモを書いています。
エミュレータ関連
エミュレータ操作のためのショートカットキー
Emulated Device Key | Keyboard Key |
Home | HOME (Mac: fn + left key) |
Menu (left softkey) | F2 or Page-up button |
Star (right softkey) | Shift-F2 or Page Down |
Back | ESC |
Call/dial button | F3 |
Hangup/end call button | F4 |
Search | F5 |
Power button | F7 |
Audio volume up button | KEYPAD_PLUS, Ctrl-F5 |
Audio volume down button | KEYPAD_MINUS, Ctrl-F6 |
Camera button | Ctrl-KEYPAD_5, Ctrl-F3 |
Switch to previous layout orientation (for example, portrait, landscape) | KEYPAD_7, Ctrl-F11 |
Switch to next layout orientation (for example, portrait, landscape) | KEYPAD_9, Ctrl-F12 |
Toggle cell networking on/off | F8 |
Toggle code profiling | F9 (only with -trace startup option) |
Toggle fullscreen mode | Alt-Enter |
Toggle trackball mode | F6 |
Enter trackball mode temporarily (while key is pressed) | Delete |
DPad left/up/right/down | KEYPAD_4/8/6/2 |
DPad center click | KEYPAD_5 |
Onion alpha increase/decrease | KEYPAD_MULTIPLY(*) / KEYPAD_DIVIDE(/) |
ネットワークアドレス
10.0.2.1 | Router/gateway address |
10.0.2.2 | Special alias to your host loopback interface (i.e., 127.0.0.1 on your development machine) |
10.0.2.3 | First DNS server |
10.0.2.4 / 10.0.2.5 / 10.0.2.6 | Optional second, third and fourth DNS server (if any) |
10.0.2.15 | The emulated device's own network/ethernet interface |
127.0.0.1 | The emulated device's own loopback interface |
エミュレータを動作させている開発環境とネットワーク通信を行いたい場合は上記の通り''10.0.2.2''を参照すれば良いです。
NDK(JNI)関連
JNIHelp
JNIで呼び出される関数名はパッケージ名、クラス名、メソッド名を連結した名前を付ける必要があり可読性を著しく損なう原因となっています。そこで、JNIから呼び出される関数をパッケージ単位で登録できる ''jniRegisterNativeMethods'' 関数を使うと便利です(以下抜粋)。
最適化
コンパイル時に指定できる最適化関連のオプション
$ arm-linux-androideabi-g++ --target-help The following options are target specific: -mabi= Specify an ABI -mabort-on-noreturn Generate a call to abort if a noreturn function returns -mandroid Generate code for the Android platform. -mapcs-float Pass FP arguments in FP registers -mapcs-frame Generate APCS conformant stack frames -mapcs-reentrant Generate re-entrant, PIC code -march= Specify the name of the target architecture -mbig-endian Assume target CPU is configured as big endian -mbionic Use Bionic C library -mcallee-super-interworking Thumb: Assume non-static functions may be called from ARM code -mcaller-super-interworking Thumb: Assume function pointers may go to non- Thumb aware code -mcirrus-fix-invalid-insns Cirrus: Place NOPs to avoid invalid instruction combinations -mcpu= Specify the name of the target CPU -mfix-cortex-m3-ldrd Avoid overlapping destination and address registers on LDRD instructions that may trigger Cortex-M3 errata. -mfloat-abi= Specify if floating point hardware should be used -mfp16-format= Specify the __fp16 floating-point format -mfpu= Specify the name of the target floating point hardware/format -mglibc Use GNU C library -mhard-float Alias for -mfloat-abi=hard -mlittle-endian Assume target CPU is configured as little endian -mlong-calls Generate call insns as indirect calls, if necessary -mpic-register= Specify the register to be used for PIC addressing -mpoke-function-name Store function names in object code -msched-prolog Permit scheduling of a function's prologue sequence -msingle-pic-base Do not load the PIC register in function prologues -msoft-float Alias for -mfloat-abi=soft -mstructure-size-boundary= Specify the minimum bit alignment of structures -mthumb Compile for the Thumb not the ARM -mthumb-interwork Support calls between Thumb and ARM instruction sets -mtp= Specify how to access the thread pointer -mtpcs-frame Thumb: Generate (non-leaf) stack frames even if not needed -mtpcs-leaf-frame Thumb: Generate (leaf) stack frames even if not needed -mtune= Tune code for the given processor -muclibc Use uClibc C library -mvectorize-with-neon-quad Use Neon quad-word (rather than double-word) registers for vectorization -mword-relocations Only generate absolute relocations on word sized values. -mwords-little-endian Assume big endian bytes, little endian words Known ARM CPUs (for use with the -mcpu= and -mtune= options): cortex-m0, cortex-m1, cortex-m3, cortex-m4, cortex-r4f, cortex-r4, cortex-a15, cortex-a9, cortex-a8, cortex-a5, arm1156t2f-s, arm1156t2-s, mpcore, mpcorenovfp, arm1176jzf-s, arm1176jz-s, arm1136jf-s, arm1136j-s, arm1026ej-s, arm926ej-s, fa726te, fmp626, fa626te, fa606te, iwmmxt2, iwmmxt, xscale, arm1022e, arm1020e, arm10e, arm968e-s, arm966e-s, arm946e-s, arm9e, arm1020t, arm10tdmi, ep9312, arm940t, arm922t, arm920t, arm920, arm9tdmi, arm9, arm740t, arm720t, arm710t, arm7tdmi-s, arm7tdmi, fa626, fa526, strongarm1110, strongarm1100, strongarm110, strongarm, arm810, arm8, arm7dmi, arm7dm, arm7m, arm7500fe, arm7500, arm7100, arm710c, arm720, arm710, arm700i, arm700, arm70, arm7di, arm7d, arm7, arm620, arm610, arm600, arm60, arm6, arm3, arm250, arm2 Known ARM architectures (for use with the -march= option): iwmmxt2, iwmmxt, ep9312, armv7e-m, armv7-m, armv7-r, armv7-a, armv7, armv6-m, armv6t2, armv6zk, armv6z, armv6k, armv6j, armv6, armv5te, armv5e, armv5t, armv5, armv4t, armv4, armv3m, armv3, armv2a, armv2 Assembler options ================= Use "-Wa,OPTION" to pass "OPTION" to the assembler. ARM-specific assembler options: -k generate PIC code -mthumb assemble Thumb code -mthumb-interwork support ARM/Thumb interworking -mapcs-32 code uses 32-bit program counter -mapcs-26 code uses 26-bit program counter -mapcs-float floating point args are in fp regs -mapcs-reentrant re-entrant code -matpcs code is ATPCS conformant -mbig-endian assemble for big-endian -mlittle-endian assemble for little-endian -mapcs-frame use frame pointer -mapcs-stack-check use stack size checking -mno-warn-deprecated do not warn on use of deprecated feature -mcpu=<cpu name> assemble for CPU <cpu name> -march=<arch name> assemble for architecture <arch name> -mfpu=<fpu name> assemble for FPU architecture <fpu name> -mfloat-abi=<abi> assemble for floating point ABI <abi> -meabi=<ver> assemble for eabi version <ver> -mimplicit-it=<mode> controls implicit insertion of IT instructions -EB assemble code for a big-endian cpu -EL assemble code for a little-endian cpu --fix-v4bx Allow BX in ARMv4 code
FPU(浮動小数点演算ユニット)関連のオプション
VFP/NEON関連のオプションです。
- ''ハードウェアFPUを利用''
mfloat-abi オプションで指定します。-mfloat-abi=softfp
を指定してコンパイルすると.fpu vfp ... fmsr s15, r3 @int fsitos s0, s15
このようにVFP(Vector Floating-Point, ARMv6)命令を使います。
- ''FPUの指定''
mfpu オプションで利用するFPUを指定できます。-mfloat-abi=softfp -mfpu=vfpv3-d16
このようにFPU名を明示します。.fpu vfpv3-d16 ... fmsr s15, r3 @int fsitos s0, s15
- ''NEONを利用したベクトル化''
ベクトル化のオプションを追加指定します。-mfloat-abi=softfp -mfpu=neon -ftree-vectorize -mvectorize-with-neon-quad
mfpu オプションでNEONを指定し、ftree-vectorize オプションでループのベクトル化を、mvectorize-with-neon-quad オプションでQレジスタ(128bitレジスタ)を利用するように指定します。.fpu neon ... vmla.i32 q8, q10, q9 vst1.32 {q8}, [ip]!
これでNEON(ARMv7)命令を使うようになります。-mfloat-abi=softfp は値の名前で勘違いしそうですが、浮動小数点演算をエミュレーション実行しているわけではなくハードウェア(FPU)で演算してくれます。このオプションはABI(Application Binary Interface)を指定するもので、関数呼び出し時のレジスタの使われ方が異なります。FPUがない(soft)場合との互換性が取れるように、ハードウェアFPUで関数によって演算が実行される場合でも浮動小数点引数は整数レジスタ(r)に渡されます。
参考: ハードウェア VFP 命令の使用
数学演算関連のオプション
- ffast-math オプション
これはAndroid特有のものではなくGCC一般の最適化オプションです。このオプションを指定すると次のオプションを一度に指定したことになります。-fno-math-errno -funsafe-math-optimizations -fno-trapping-math -ffinite-math-only -fno-signaling-nans
実行速度最適化のためANSIやIEEEの規則や仕様を破ることをGCCに許します。例えば、sqrt 関数の引数が負にならないと仮定したりとか。結果として浮動小数点演算の精度が変わってしまうような最適化でも行うようになります。精度を重視する場合は指定しないようにしましょう。O3オプションを併せて指定されることが多いです。
ndk-buildコマンド
ndk-buildをコマンドラインから実行する際にコンパイルオプションなどを標準出力で確認したい場合は
$ ndk-build V=1
のように Vオプション を指定すれば確認できます。
開発での注意点、SDKバグ関連
XMLパーサー
Android 4.0 (Ice Cream Sandwich) から''XmlPullParser''のコア部分が変更となったため(バグの多いExpatPullParserが削除されKXmlParserに統一)、Android 3.2以前のプロジェクトで動作していたXMLを扱うプログラムが4.0以降では動作しなくなる可能性があります。
参考: Watch out for XmlPullParser.nextText()
画像処理/カメラ関連
画像処理を行うAndroidアプリ開発はメモリとの戦いです。とにかく OutOfMemory エラーが多発します。。
- android.graphics.BitmapFactory 画像のデコードに合計32KBしか使えない模様。ただし、tempStorage の方は任意に指定できる(?
- カメラデバイスオープン時の注意点
カメラデバイスを開くときに(android.hardware.Camera#open)、API Level 11(Android 3.0)未満ではカメラ処理の種類を明示的に指定(android.view.SurfaceHolder#setType)しておかないとアプリが落ちてしまいます。
SURFACE_TYPE_PUSH_BUFFERS を指定すると「バッファに入れられた画像を画面表示する(カメラプレビュー)」という処理になります。
OpenCV for Android
OpenCV for Androidについては別ページに。
Androidソースコードリーディング
まだ殴り書きのメモ段階です、コードリーディングを進めながら整理していきます
Androidのソースコードリーディングを進めています。
Welcome to Android
- 構成 platform
bionic glibc互換 Cライブラリ bootable ブート関連 build ビルドツール cts 互換性確認ツール dalvik 仮想マシン(DalvikVM) development 開発ツール(エミュレータとか) device デバイス関連ファイル external 外部で開発されたソフトなど frameworks Android フレームワーク hardware ハードウェア制御ライブラリ ndk Native Development Kit packages 標準インストールアプリ prebuilt ビルドツール(ビルド済) sdk Android SDK system デバイスドライバのソース
- 名前の由来
「GoogleのDan Bornsteinが自作の仮想マシンに付けたDalvikという名前は、祖先がむかし住んでいたアイスランドの漁村の名に由来している。」 とのこと。
- きっかけ
主にNDK(JNI)を用いた開発中、スタックトレースに見慣れない単語(Zygoteなど)が頻発するため中身を知りたいと思ったから。at com.android.internal.os.ZygoteInit.main at dalvik.system.NativeStart.main
とか、あとは画像処理アプリを作っているときはよくメモリが足りなくてつまづくことが多いです。ERROR/dalvikvm-heap(187): 2457600-byte external allocation too large for this process. ERROR/(187): VM won't let us allocate 2457600 bytes… ERROR/AndroidRuntime(187): java.lang.OutOfMemoryError: bitmap size exceeds VM budget
などのエラー
Zygote
Androidアプリケーションはマルチタスクで実行することができますが、ここではその仕組みを調べます。
Androidを起動すると、まずZygote(ザイゴウト)というプロセスが立ち上がります(いわゆるinitプロセス)。このZygoteはすべてのAndroidアプリケーションの親プロセスになっています。アプリケーションを起動するには下図のようにZygoteから fork して子プロセスを作ります。
Zygoteは多くのライブラリを含んでいるため起動には時間がかかりますが、その後の子プロセス生成は非常に高速に行うことができます。また、子プロセスは親プロセスとメモリ領域を共有するためメモリ消費量も節約できます。
ここで、Zygoteプロセス起動からのフローを整理します。
- init.rc
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
initでサービスを起動します。エントリーポイントは以下のようになっています。 - frameworks/base/cmds/app_process/app_main.cpp
- frameworks/base/core/jni/AndroidRuntime.cpp 続きは調べつつ書きます。
ashmem (Anonymouse Shared memory Subsystem)
Androidにおける共有メモリ用デバイスで、Linuxカーネルに組み込まれています。ashmem からメモリを確保するには /dev/ashmem をオープンして mmap を使います。mmap を行うと ashmem デバイスを通じて最終的に tmpfs からデータを取得します。
ashmem API
ashmemの機能は libcutils.so に含まれています。
- system/core/include/cutils/ashmem.h
ashmemの提供するAPIは以下の5つ。内部では ioctl でデバイスドライバに情報を渡しているだけ。 共有メモリ領域生成には以下のように ashmem_create_region で返ってくるファイルディスクリプタを mmap に渡します。 他のプロセスから共有メモリを使うには binder (Android独自のデバイスドライバ)経由で使うようです。要調査。
Android SDKではJavaから ashmem を利用するために、''android.os.MemoryFile'' クラスが提供されています。アプリケーションキャッシュなどに利用すると良いです。また、 ashmem はグラフィックメモリのバッファなどでも利用されているとのことです。
binder
プロセス間通信
atodekaku
bionic
bionic はAndroidのCライブラリです。 glibc は組み込み向けには大きすぎるため BSD libc をAndroid向けに改良したライブラリが用いられています。
dlmalloc
(ここではv2.8.6を対象としています)
bionic にはDoug Leaという方が作った通称 dlmalloc と呼ばれるメモリ確保機構が含まれています。dlmalloc は速度と空間効率を両立したアルゴリズムを採用しており、フラグメンテーションの問題を最小限にします。スマートフォンデバイスのような組み込み環境に適しているとのことです。
- platform/bionic/libc/upstream-dlmalloc
以下のようにメモリ確保関数を #define して使うことができます。
まず create_mspace() で指定したサイズ(capacity, 0ならデフォルトの粒度)の領域をあらかじめ確保し、そこから必要なサイズの領域を mspace_malloc() で取得します。デフォルトで確保される領域については以下の通りです。
フリーリストは''循環双方向リンクリスト''あるいは''トライ木(trie)''(内部では bin と呼ばれている)で管理されています。チャンク(リストのノード)のサイズは、フリーチャンクの最後の4バイトにも記録されています。これを活用して隣接するフリーチャンクを結合してメモリの断片化を避けています。各binはサイズ別にチャンクを管理しており、求めるサイズのチャンクをすばやく探せるようになっています。チャンクを解放するとき、可能であれば隣り合うフリーチャンクと結合させます(断片化防止)。解放するチャンクの直前または直後に位置するチャンクがフリーであれば、そのフリーチャンクはbinから外され、解放しようとしているチャンクと結合して適切なbinに配置されます。チャンクの構造は以下のようになっています。
実は glibc malloc は dlmalloc から派生したもの、歴史はとても古いのです。シンプルな仕組みなのに効率が良く、現在でも広く利用されています。詳細は本家サイトにて、図付きでわかりやすいです。
A Memory Allocator
DEXファイルフォーマット
Androidアプリは、それぞれが独自のLinuxプロセス内で実行され、それらのプロセスが個々にDalvik VMのインスタンスをホストしています。Dalvikは、デバイスが複数の仮想マシンを同時に効率よく実行できるように設計されています。効率が良い理由は、主にDalvikがDEX(Dalvik Executable)ベースのファイルを実行するからです。DEXはメモリの占有を最小限に抑えるよう最適化されたフォーマットです。
.dex — Dalvik Executable Format
データ型
DEXファイルフォーマットで扱えるデータ型は以下の11種類です。また、バイトオーダーはリトルエンディアンとなっています。
Name | Description |
byte | 8ビット符号付き整数 |
ubyte | 8ビット符号無し整数 |
short | 16ビット符号付き整数 |
ushort | 16ビット符号無し整数 |
int | 32ビット符号付き整数 |
uint | 32ビット符号無し整数 |
long | 64ビット符号付き整数 |
ulong | 64ビット符号無し整数 |
sleb128 | 符号付きLEB128 (後述) |
uleb128 | 符号無しLEB128 (後述) |
uleb128p1 | 符号無しLEB128 + 1 |
LEB128(Little-Endian Base 128)では可変長整数を扱います。これは DWARF3 フォーマットを参考にしたもので以下のような構造(2バイトの場合)になっています。
| Bitwise diagram of a two-byte LEB128 value | | First byte | Second byte | | 1 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 | 0 | bit13 | bit12 | bit11 | bit10 | bit9 | bit8 | bit7 |
各バイトの7ビットがデータで最上位ビットを使ってデータの終端を示しています。上の例だと2バイト目の最上位ビットが落ちているため、ここでこのデータは終了ということになります。値の大きさによってデータ長も変化するので、小さな整数値だとデータ長も短くなります。LEB128のような可変長整数の扱い方は特に珍しくはなく、バイナリネットワークプロトコルだとよく見かけます(thriftとか)。
ファイルレイアウト
内部のセクションは以下のようになっています。
header | ヘッダ |
string_ids | 文字列(UTF-16)を格納 |
type_ids | データ型を格納 |
proto_ids | メソッドのプロトタイプ情報(戻り値の型とか)を格納 |
field_ids | クラスのフィールド情報を格納 |
method_ids | クラスのメソッド情報を格納 |
class_defs | クラス情報(継承関係とか)を格納 |
data | データを格納、アノテーション情報も含む |
link_data | 静的リンクされたファイルのデータを格納 |
型のシグネチャはJNIを利用するときにもよく目にします。以下にシグネチャと型の対応を載せます。
V | void; only valid for return types |
Z | boolean |
B | byte |
S | short |
C | char |
I | int |
J | long |
F | float |
D | double |
Lfully/qualified/Name; | the class fully.qualified.Name |
[descriptor | array of descriptor, usable recursively for arrays-of-arrays, though it is invalid to have more than 255 dimensions. |
最後の配列型は例えば "[I" ならint型配列、"[D" ならdouble型配列を表します。
''Dalvik VMはJavaバイトコードを実行しません。''コンパイルされたJavaのクラスファイル(.class)をDEXファイル(.dex)に変換して生成されたバイトコードが実行されます。
- ''dx''
classファイルをdexファイルに変換できるコマンド。Android SDKに入っています。$ dx usage: dx --dex [--debug] [--verbose] [--positions=<style>] [--no-locals] [--no-optimize] [--statistics] [--[no-]optimize-list=<file>] [--no-strict] [--keep-classes] [--output=<file>] [--dump-to=<file>] [--dump-width=<n>] [--dump-method=<name>[*]] [--verbose-dump] [--no-files] [--core-library] [--num-threads=<n>] [--incremental] [--force-jumbo] [<file>.class | <file>.{zip,jar,apk} | <directory>] ... Convert a set of classfiles into a dex file, optionally embedded in a jar/zip. Output name must end with one of: .dex .jar .zip .apk. Positions options: none, important, lines. dx --annotool --annotation=<class> [--element=<element types>] [--print=<print types>] dx --dump [--debug] [--strict] [--bytes] [--optimize] [--basic-blocks | --rop-blocks | --ssa-blocks | --dot] [--ssa-step=<step>] [--width=<n>] [<file>.class | <file>.txt] ... Dump classfiles, or transformations thereof, in a human-oriented format. dx --find-usages <file.dex> <declaring type> <member> Find references and declarations to a field or method. declaring type: a class name in internal form, like Ljava/lang/Object; member: a field or method name, like hashCode dx -J<option> ... <arguments, in one of the above forms> Pass VM-specific options to the virtual machine that runs dx. dx --version Print the version of this tool (1.7). dx --help Print this message.
実際にAndroidプロジェクトディレクトリで以下のようにコマンドを実行してみます。--output オプションで出力ファイル名を指定し、その後に変換対象のclassファイルを含んだディレクトリを指定します。$ dx --dex --verbose --output=classes.dex bin/classes ignored resource bin/classes/./.DS_Store ignored resource bin/classes/./com/.DS_Store ignored resource bin/classes/./com/example/.DS_Store processing bin/classes/./com/example/hellojni/BuildConfig.class... processing bin/classes/./com/example/hellojni/MainActivity$1.class... processing bin/classes/./com/example/hellojni/MainActivity$2.class... processing bin/classes/./com/example/hellojni/MainActivity.class... processing bin/classes/./com/example/hellojni/R$attr.class... processing bin/classes/./com/example/hellojni/R$drawable.class... processing bin/classes/./com/example/hellojni/R$id.class... processing bin/classes/./com/example/hellojni/R$layout.class... processing bin/classes/./com/example/hellojni/R$menu.class... processing bin/classes/./com/example/hellojni/R$string.class... processing bin/classes/./com/example/hellojni/R$style.class... processing bin/classes/./com/example/hellojni/R.class...
カレントディレクトリに classes.dex ファイルが生成されていたら成功です。このdexファイルは後述の dexdump コマンドで中身を覗くことができます。
Dalvik VMバイトコード
Dalvik VMは''レジスタマシン''として実装されています(JVMはスタックマシン)。Dalvik VMバイトコードの特徴を整理します。
- オペコードは8ビットで、これに必要な分だけオペランドが追加される
- 命令は16ビット単位でアライメントされる(16-bit code units)
- 各命令毎に指定できるレジスタ番号の異なり、4/8/16ビットの範囲の番号で指定する
Dalvik VMで実行されるバイトコードについて、以下の公式リファレンスを見ながら dexdump コマンドを使って整理していきます。
Bytecode for the Dalvik VM
- ''dexdump''
Unix系OSでELFバイナリを読むときに使う objdump のようなもの。 前述の dx コマンドと同様にこれもAndroid SDKに入っています。$ dexdump dexdump: no file specified Copyright (C) 2007 The Android Open Source Project dexdump: [-c] [-d] [-f] [-h] [-i] [-l layout] [-m] [-t tempfile] dexfile... -c : verify checksum and exit -d : disassemble code sections -f : display summary information from file header -h : display file header details -i : ignore checksum failures -l : output layout, either 'plain' or 'xml' -m : dump register maps (and nothing else) -t : temp file name (defaults to /sdcard/dex-temp-*)
以下のような簡単なJavaコードをコンパイルしてclassファイルを作り、それを dx コマンドでdexファイルに変換。 dexdump コマンドを使ってその中身を覗いてみます。
コードをディスアセンブルするには -d オプションを付けて実行します。
Helloworldクラスでは単純な演算命令しか使っていないのでバイトコードを読むのも楽だと思います。
/dalvik/vm/mterp/out 以下にアーキテクチャ毎のバイトコードインタプリタのコードが入っています。
$ ls dalvik/vm/mterp InterpAsm-allstubs.S InterpAsm-armv7-a-neon.S InterpAsm-x86.S InterpC-armv5te.cpp InterpC-mips.cpp InterpAsm-armv5te-vfp.S InterpAsm-armv7-a.S InterpC-allstubs.cpp InterpC-armv7-a-neon.cpp InterpC-portable.cpp InterpAsm-armv5te.S InterpAsm-mips.S InterpC-armv5te-vfp.cpp InterpC-armv7-a.cpp InterpC-x86.cpp
ガベージコレクション
Dalvik VMのGCには''Mark & Sweep(ビットマップマーキング)''アルゴリズムを採用しています。通常のMark & Sweep方式はLinuxのCopy On Write(データの書き換えが発生した時にコピーを行う)と相性が悪いです。Mark & Sweepは生きているオブジェクトのヘッダにマークビットを立てますが、これを行うと本来は必要のないコピーが行われてしまうからです。なので、Dalvik VMではビットマップマーキングという手法を併用してこの問題に対処しています。この手法は各オブジェクトのマークビットだけを集めたテーブル(ビットマップテーブル)を用意し、オブジェクトとは別の場所で管理する手法です。
- dalvik/vm/alloc
$ ls Alloc.cpp Copying.cpp DlMalloc.h HeapBitmap.h HeapInternal.h MarkSweep.h Visit.cpp Alloc.h DdmHeap.cpp Heap.cpp HeapBitmapInlines.h HeapSource.cpp TEST/ Visit.h CardTable.cpp DdmHeap.h Heap.h HeapDebug.cpp HeapSource.h Verify.cpp VisitInlines.h CardTable.h DlMalloc.cpp HeapBitmap.cpp HeapDebug.h MarkSweep.cpp Verify.h WriteBarrier.h $ du -sh *.cpp 12K Alloc.cpp 16K CardTable.cpp 72K Copying.cpp 16K DdmHeap.cpp 4.0K DlMalloc.cpp 24K Heap.cpp 8.0K HeapBitmap.cpp 4.0K HeapDebug.cpp 40K HeapSource.cpp 28K MarkSweep.cpp 4.0K Verify.cpp 12K Visit.cpp
Dalvik VMのヒープ
Dalvik VMのオブジェクトは専用のヒープに保持されます。これには2種類あり、1つは前述の Zygote 用のヒープ、もう1つはAndroidアプリケーションで使用するヒープです。ヒープの中身は以下のようになっています。
- dalvik/vm/alloc/HeapSource.cpp 前述の dlmalloc の項で紹介した mspace をメンバとして持っています。オブジェクトはこの中にアロケーションされます。
- dalvik/vm/alloc/HeapBitmap.h
マーキングで用いるビットマップは以下のように定義されています。実態は unsigned long の配列のようです。 処理の詳細については調べながら追記していきます。