2011年11月23日水曜日

Releasing statement in a finalizer

Releasing statement in a finalizer

下記の趣旨の警告が出た。
WARN/SQLiteCompiledSql: Releasing statement in a finalizer. Please ensure that you explicitly call close() on your cursor:
WARN/SQLiteCompiledSql: android.database.sqlite.DatabaseObjectNotClosedException: Application did not close the cursor or database object that was opened here

WARN/SQLiteCompiledSqlと書かれてあるため、データベース関係が原因であろうと想像する。databaseをcloseすれば解決はできる。他のサイトを見ても、同様の趣旨の回答が書かれてある。警告に書かれてあるとおりであるので、何も問題は無い。

しかし、私のアプリの場合、そこでcloseをしてはいけないのである。データベースを使い続けたいのである。

解決のヒントはfinalizerであった。finalizerをキーワードにして調べた。
参考:

上記エラーが発生するのは、エミュレータである。実機では発生しない。
そこで、エミュレータのheapサイズを、デフォルトの24から200に増やしてみた。すると、上記警告は発生しなくなった。
設定方法は次のとおりである。
Window>Android SDK and AVD Manager>AVDを編集する画面を表示させる。
Target欄に適当な事項を設定すると、HardWare欄にMax VM application heap sizeの行が表示されるので、そこのValueを24から200に変えれば良い。

これで問題の原因が特定できた。ガベージコレクション(garbage collection; GC)の仕掛けが原因であった。heapサイズが小さい場合、警告を発するのである。

これは、警告が発せられたという程度の問題である。データベースを破棄しているのではない。なのでアプリとしての実害は無い。
データベースを引き続きそのまま使い続けたいなら、警告を無視すれば良い。
ただし、ズラズラと長いメッセージが表示されるのは迷惑なので、heap sizeを大きくすれば良い。

追記(2012年5月3日)
heap sizeを大きくしてみたところ、エミュレーターが起動しなくなった。そこで、heap size以外の方法で対処することにした。
実は、この警告が発生する箇所では、SQLiteStatement Classを使ってレコードのINSERTを行っていた。
SQLiteStatement Classを使うのをやめて、ContentValues Classを使う方法にした。
すると、警告は出なくなった。
むむむ!

参考:ContentValues Classのsample code
                ContentValues v;
                v = new ContentValues();
                v.put("Item1", "aaa");
                v.put("Item2", "bbb");
                mDb.insert("MyTable", null, v);

0 件のコメント:

コメントを投稿