【问题标题】:Android SQLite memory leakAndroid SQLite 内存泄漏
【发布时间】:2010-09-15 17:54:05
【问题描述】:

我知道这是一篇很长的帖子。请不要介意。

Leak found
E/Database( 4549): java.lang.IllegalStateException: mPrograms size 1
E/Database( 4549):  at android.database.sqlite.SQLiteDatabase.finalize(SQLiteDatabase.java:1668)
E/Database( 4549):  at dalvik.system.NativeStart.run(Native Method)
E/Database( 4549): Caused by: java.lang.IllegalStateException: /data/data/com.rjblackbox.droid.fvt/databases/fvt.db SQLiteDatabase created and never closed
E/Database( 4549):  at android.database.sqlite.SQLiteDatabase.<init>(SQLiteDatabase.java:1694)
E/Database( 4549):  at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:738)
E/Database( 4549):  at android.database.sqlite.SQLiteDatabase.openOrCreateDatabase(SQLiteDatabase.java:760)
E/Database( 4549):  at android.database.sqlite.SQLiteDatabase.openOrCreateDatabase(SQLiteDatabase.java:753)
E/Database( 4549):  at android.app.ApplicationContext.openOrCreateDatabase(ApplicationContext.java:473)
E/Database( 4549):  at android.content.ContextWrapper.openOrCreateDatabase(ContextWrapper.java:193)
E/Database( 4549):  at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:98)
E/Database( 4549):  at com.rjblackbox.droid.fvt.FVTDataHelper.<init>(FVTDataHelper.java:37)
E/Database( 4549):  at com.rjblackbox.droid.fvt.FVTNotificationService.getNextEntry(FVTNotificationService.java:91)
E/Database( 4549):  at com.rjblackbox.droid.fvt.FVTNotificationService.access$2(FVTNotificationService.java:90)
E/Database( 4549):  at com.rjblackbox.droid.fvt.FVTNotificationService$1.run(FVTNotificationService.java:53)
E/Database( 4549):  at android.os.Handler.handleCallback(Handler.java:587)
E/Database( 4549):  at android.os.Handler.dispatchMessage(Handler.java:92)
E/Database( 4549):  at android.os.Looper.loop(Looper.java:123)
E/Database( 4549):  at android.app.ActivityThread.main(ActivityThread.java:4363)
E/Database( 4549):  at java.lang.reflect.Method.invokeNative(Native Method)
E/Database( 4549):  at java.lang.reflect.Method.invoke(Method.java:521)
E/Database( 4549):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:860)
E/Database( 4549):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618)
E/Database( 4549):  at dalvik.system.NativeStart.main(Native Method)

这是我的内存泄漏的堆栈跟踪。下面是我的数据助手的源代码。除了 Activity,我还有一个访问数据的 Service。对于有经验的开发人员来说,这一定是小菜一碟。

public class FVTDataHelper {
    private static final String DB_NAME = "fvt.db";
    private static final int DB_VERSION = 1;

    private static final String TABLE_TIMERS = "timers";
    private static final String[] TABLE_TIMERS_COLUMNS = {"id", "name", "added", "expires"};
    private static final String TIMER_INSERT = "INSERT INTO " + 
    TABLE_TIMERS + "('name', 'added', 'expires') VALUES (?, ?, ?)";

    private SQLiteDatabase db;
    private Cursor c;
    private SQLiteStatement timerInsert;

    //Constructor
    public FVTDataHelper(Context ctx) {
        OpenHelper oh = new OpenHelper(ctx);
        db = oh.getWritableDatabase();
        timerInsert = db.compileStatement(TIMER_INSERT);
    }

    public void addTimerEntry(TimerEntry entry) {
        String name = entry.getName();
        long added = entry.getAdded();
        long expires = entry.getExpires();

        timerInsert.bindString(1, name);
        timerInsert.bindString(2, Long.toString(added));
        timerInsert.bindString(3, Long.toString(expires));
        timerInsert.executeInsert();
    }

    public List<TimerEntry> getTimerEntries() {
        ArrayList<TimerEntry> entries = new ArrayList<TimerEntry>();
        c = db.query(TABLE_TIMERS, TABLE_TIMERS_COLUMNS, null, null, null, null, "expires asc");

        if(c.moveToFirst()) {
            int id;
            String name;
            long added;
            long expires;

            do {
                id = c.getInt(0);
                name = c.getString(1);
                added = c.getLong(2);
                expires = c.getLong(3);

                if((System.currentTimeMillis() - added) >= 0) {
                    entries.add(new TimerEntry(id, name, added, expires));
                }
            } while(c.moveToNext());
        }
        c.close();
        return entries;
    }

    public void deleteTimerEntry(int id) {
        db.delete(TABLE_TIMERS, "id=" + id, null);
    }

    //Helper class for creating and updating database 
    private static class OpenHelper extends SQLiteOpenHelper {
        private Context ctx;

        public OpenHelper(Context ctx) {
            super(ctx, DB_NAME, null, DB_VERSION);
            this.ctx = ctx;
        }

        @Override
        public void onCreate(SQLiteDatabase db) {
            String sqlDump = getSQLDump();

            String[] statements = sqlDump.split("\n");
            for(String statement : statements) {
                if(DEBUG) Log.d(TAG, statement);
                db.execSQL(statement);
            }
        }

        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
            onCreate(db);
        }

        //Helper: Returns SQL statements from the dump
        private String getSQLDump() {
            StringBuilder sb = new StringBuilder();
            try {
                InputStream is = ctx.getAssets().open("dump.sql");
                int c;
                while((c = is.read()) != -1) {
                    sb.append((char) c);
                }
                is.close();
            } catch (IOException e) {
                Log.d(TAG, e.getMessage());
            }
            return sb.length() > 0 ? sb.toString() : ";";
        }
    }
}

【问题讨论】:

  • 代码运行良好。并且该应用程序运行良好。我只想处理这个内存泄漏。
  • 不完全是内存泄漏

标签: sql android sqlite


【解决方案1】:

您需要在重新打开数据库之前关闭数据库,堆栈跟踪消息非常清楚问题所在。

一种解决方案是利用android.app.Application 类并将打开的数据库实例存储在其中。如果您这样做,请务必使用Application 上下文而不是Activity 上下文打开数据库,否则您可能会在您的活动被销毁时泄漏上下文。

另一种解决方案是在onDestroy/onStop等中关闭数据库并在onCreate/onStart等中重新打开。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-11-14
    • 2011-12-31
    • 1970-01-01
    • 1970-01-01
    • 2011-06-11
    • 2012-11-14
    • 2014-08-05
    相关资源
    最近更新 更多