2011年2月15日火曜日

Android で OSGi を使うべきでない理由

Android の仮想マシンである Dalvik VM がクラスのアンローディングに対応していないので、OSGi バンドルのインストールとアンインストールを繰り返すと、やがてはメモリ不足に陥り、Dalvik VM が突然終了してしまう。しかも、そのメモリ不足は、システムのRAM総量による制限ではなく、ソースコードの中で次のように固定的に定義されている定数値による制限である。

  #define DEFAULT_MAX_LENGTH  (5*1024*1024)

また、突然終了というのは、意図的に Segmentation Fault を起こすことによる Dalvik VM アボートである。

Dalvik VM のクラスローダの実装は、かなり悪い。クラスローダ毎に管理しなければならないデータを、一個のグローバル変数で管理している。ブートストラップクラスローダとユーザ定義のクラスローダの違いは無視される。たとえば、ロードされた全てのクラスは、クラスローダの区別なく、グローバル変数 gDvm.loadedClasses というハッシュテーブルに格納される。そして、このハッシュテーブルに登録されているクラスは、Mark and Sweep ガベージコレクションのマーク処理のフェーズで、そのクラスのインスタンスが残っているかどうかに関係なく、無条件にマーク対象となる。結果的に、あるユーザ定義クラスローダがロードしたクラスのインスタンス群の参照が全て無くなり、クラスおよびクラスローダへの参照が無くなったとしても、そのクラスとクラスローダはGCに回収されることはない。

原因は上記のものとは別のところにあるが、Android に付属の java.net.URLClassLoader も当然のごとく機能しない。URLClassLoader を使うと例外が発生し、そのエラーメッセージの内容は「入力データのクラスフォーマットはサポートされていない」というものであるが、これは全く見当違いのエラーメッセージであり、実際のエラーの原因は、単なる実装不備である。

Java 仮想マシンとは別の Dalvik VM 仮想マシンを作ったことは、完全に車輪の再開発であるが、再開発するならより良いものを作るべきであった。重要な部分の互換性を放棄したにもかかわらず、機能に問題がある。得たものよりも失ったもののほうが多い。

The reason that OSGi should not be used on Android

Because Dalvik VM, which is the virtual machine of Android, does not support class-unloading, if installing and uninstalling OSGi bundles are repeated, memory shortage happens in the end and Dalvik VM suddenly terminates. What is worse, the memory shortage is caused not by the limitation of the total RAM size in the system but by the constant value which is defined in source code as follows:

  #define DEFAULT_MAX_LENGTH  (5*1024*1024)

Even worse, the sudden termination is Dalvik VM Abort which intentionally causes Segmentation Fault.

The implementation of the class loader of Dalvik VM is terribly bad. Various data which should be managed per class loader are managed by one global variable. Differences between the bootstrap class loader and user-defined class loaders are ignored. For example, all loaded classes are stored into a global hash table named 'gDvm.loadedClasses' regardless of whatever class loader loaded them. And, the classes in the hash table are unconditionally marked during the mark phase of the Mark and Sweep garbage collection regardless of whether instances of the classes are still alive or not. As a result, even if no reference to instances of classes loaded by a user-defined class loader remains and if also no reference to the classes and the class loader remains, the garbage collector never collects the classes and the class loader.

The reason exists in some other places than the above, java.net.URLClassLoader which comes along with Android does not work as if it were no wonder. Using the URLClassLoader raises an exception and the error message says that the format of the input data is not supported, but the error message is utterly off the mark. The real cause is simply the flawed implementation.

It is completely reinvention of the wheel to have developed Dalvik VM which is not a Java virtual machine, but a better one should have been developed if reinvention were done. Although important compatibilities have been abandoned, problems exist in the functionaries. There is much more lost than gained.