Tuesday, October 7, 2014

GC_EXPLICITが出ないように対策

JUST PLAYERのログをずっとみていると、次のようなログが頻繁にでていました。
 
GC_EXPLICIT freed 5773K, 34% free 27728K/41588K, paused 17ms+20ms, total 267ms
GC_EXPLICIT freed 41K, 75% free 2829K/11252K, paused 2ms+2ms, total 27ms

発生するタイミングを調べるとどうやら、ContentProviderでQueryをするタイミングだということがわかりました。


該当するクエリ処理をみてみると、どうやらsetNotificationUriが怪しい

cursor.setNotificationUri(getContext().getContentResolver(), uri);

試しに上記のコードの部分をコメントアウトすると、GC_EXPLICITがでなくなりました。
setNotificationUriは、registerContentObserverで登録されたコールバックに通知が届くようにするための設定処理なのでコメントアウトするわけにはいきません。 しかし、必要のないQueryに対しても常に設定するのは勿体ないです。 なので、ここは、必要なクエリとそうでないクエリを判別できるようにし、必要なクエリだけ設定するように変更しました。下記は自作のContentProviderのQuery処理です。

        boolean needSetNotify = false;
        if(uri.getQueryParameter("notify") != null){
            needSetNotify = true;
        }

        //クエリ処理

           Cursor cursor = queryBuilder.query(
                getSQLiteOpenHelper().getReadableDatabase(), projection, selection,
                selectionArgs, groupBy, having, sortOrder);
        
        if(needSetNotify) {
            cursor.setNotificationUri(getContext().getContentResolver(), uri);
        }


こんな感じで、自作のContentProviderに仕込んでおく。
そして、ContentObserver.onChangedのイベントが必要なクエリ結果の場合だけ、下記のようなクエリのためのUriを発行する。
 
        Uri uri = PlayOrderContentProvider.PLAYORDER_CONTENT_URI
                .buildUpon()
                .appendQueryParameter("notify", Boolean.toString(true))
                .build();

これをいれておくことで、通知が届くCursorを取得することができます。
GC_EXPLICITを回避しパフォーマンスが向上しました。
次のバージョンでFIXされます。


No comments:

Post a Comment