ホーム > デベロッパ > J2ME / MIDP プログラミング > 第 4 回 その1

第 4 回 : IM "improve" を実機に載せよう( IM "improve" のダウンサイズ)

はじめに

IM "improve" のクライアントは 40 K バイト強のアプリとなりました。

いろんなサイズ削減の技術によって IM "improve" を小さくします。


ダウンサイズと JAR 圧縮

JAR ファイルのサイズ削減には

の2段階があります。クラスファイルのサイズ削減についてまとめます。

クラスファイルの構造

全体構造

クラスファイルはバイト列で表現されます。

図1 クラスファイルの構造(全体とコンスタントプール)

表1 にそれぞれの簡単な説明を示します。

表1 クラスファイルの要素
構造 説明
マジックナンバー 有名な CA FE BA BE の4バイトです。
マイナーバージョン クラスファイルのフォーマットのバージョン (2バイト)
メジャーバージョン クラスファイルのフォーマットのバージョン (2バイト)
コンスタントプール クラスファイルのデータ領域。 詳細は下記参照
アクセスフラグ クラスのアクセス制御や性質を示すフラグ (2バイト)
クラス名 このクラスを示す CONSTANT_Class のインデックス (2バイト)
親クラス 親クラスを示す CONSTANT_Class のインデックス (2バイト)
インターフェース このクラスが実装しているインターフェースのリスト
フィールド このクラスのフィールド定義
メソッド このクラスのメソッド定義
属性リスト 付加情報など

コンスタントプール

データ領域であるコンスタントプールについてみていくことにします。図1 の中心にコンスタントプールの詳細構造を示します。 コンスタントプールはコンスタントプールエントリの配列になっていて、クラスファイルのうち 30 % 〜 50 % 以上の容量を占めています。 コンスタントプールエントリは1バイトのタグに続き、エントリごとのデータが続きます。(構造は 図1 右側)

エントリは 11 種類あります。表 2 にエントリ一覧を示します。

表2 コンスタントプールエントリ(接頭語 CONSTANT_ は以下省略)
分類 タグ(10進数) エントリ 説明 参照先
単純データ型 1 Utf8 Utf8 でエンコードされた文字列 -
3 Integer int リテラル (32bit 整数) -
4 Float float リテラル (32bit 浮動小数点) -
5 Long long リテラル (64bit 整数) -
6 Double double リテラル (64bit 浮動小数点) -
参照型 7 Class クラスまたはインターフェースへの参照 Utf8
8 String String リテラル Utf8
9 Fieldref フィールド参照 NameAndType
10 Methodref メソッドへの参照 NameAndType
11 InterfaceMethodref インターフェースへの参照 NameAndType
12 NameAndType メソッド・フィールド参照で名前と型を定義するもの Utf8

参照型エントリの参照をたどれば、最終的には文字列 Utf8 へたどりつきます(表 2)。 参照型エントリと数値データ型エントリはサイズが固定のためサイズ削減できません。メソッドやフィールドの名前として使わているだけのものは、 定義と参照に整合性があれば短くできます。

エントリの短縮と共有

簡単な例でコンスタントプールのサイズ削減を説明します。

図2 短縮と共有の模式図

図2 の「短縮前」を見てください。2つのエントリ NameAndType が それぞれ Utf8 の "Sophia" と "Cradle" を参照していたとします。 もしこの "Sophia" と "Cradle" が変更可能であった場合、たとえば1文字で "a" に変更します。(図2 「短縮後・共有前」)

ここで、エントリ "a" が2つ存在しますので、共有して、図2 「共有後」 のようにします。

プログラムで表示している文字列や型名をフィールド名やメソッド名にすることも可能です。(「ダウンサイズの実際」その 9 をご覧ください。)

Java VM の仕組みとインストラクション

Java VM がインストラクションを実行する概要を説明します。

ローカル変数配列とオペランドスタック

Java VM ではプログラム実行時には、スレッドごとに Java スタックが生成され、 そこにメソッド呼出ごとにフレームが積み上げられていきます。

フレームの中には、ローカル変数領域と、オペランドスタック領域があります。(図3 参照)

図3 Java スタックの構造

Java VM のローカル変数は Java 言語のローカル変数と同様に、 メソッドの実行中にだけ存在する値の格納場所ですが、 名前ではなくインデックスで指定され、 インスタンスへの参照・メソッド引数・( Java 言語での)メソッドのローカル変数などを 保存するために使用します。

オペランドスタックはインストラクションの引数・返値用の一時保存場所で、 値を積み上げてインストラクションを実行すると、引数として積み上げた値は取り出され、 結果が積み上げられます。

インストラクションの機能分類

インストラクションを分類して概要を示します。型や細かい挙動でバリエーションが多くあるものは、「系」として分類しています。

データ操作 (表3)
大分類 機能 インストラクション
スタック 定数をスタックに積む push系, ldc系, const系
スタックの編集 nop, pop系, dup系, swap
ローカル変数 ローカル変数から取り出した値を
スタックに積む
load 系
スタックから pop した値を
ローカル変数に格納する
store 系
その他 iinc, wide
配列 配列の生成 newarray, anewarray, multianewarray
配列から値を取り出す aload系
配列に値を格納する astore系
その他 arraylength
オブジェクト 新規生成 new
フィールドへのアクセス putfield, getfield, putstatic, getstatic
その他 checkcast, instatnceof
演算と型変換 (表4)
機能 インストラクション
算術演算 add系, sub系, mul系, div系, rem系, neg系
論理演算 sh系, and系, or系, xor系
型変換 2系
フロー制御 (表5)
大分類 機能 インストラクション
実行位置の移動など 条件分岐 if系
比較 cmp系
無条件分岐とサブルーチン goto系, jsr系, ret系
テーブルジャンプ lookupswitch, tableswitch
メソッド 呼び出し invokevirtual, invokespecial, invokestatic,
invokeinterface
リターン retrun系
その他 (表6)
機能 インストラクション
例外 athrow
デバッグ breakpoint
モニタ monitorenter, monitorexit