安卓_数据库泄露_安卓数据库app

安卓_数据库泄露_安卓数据库app今天遇到系统提示数据库泄露了不过找了好久也m

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

今天遇到系统提示数据库泄露了

不过找了好久也没找到。最后搜索下方案。

添加多下面这段红色的代码。就可以帮助你及时的找到问题。

import android.os.StrictMode;

public class TestActivity extends Activity {
    private static final boolean DEVELOPER_MODE = true;
    public void onCreate() {
        if (DEVELOPER_MODE) {
            StrictMode.setVMPolicy(new StrictMode.VMPolicy.Builder() .detectLeakedSqlLiteObjects() .detectLeakedClosableObjects() .penaltyLog() .penaltyDeath() .build());
        }
        super.onCreate();
    }
}

对于 APP 开发人员

从 GINGERBREAD(安卓2.3版本) 开始 Android 就提供了 StrictMode 工具协助开发人员检查是否不小心地做了一些不该有的操作。

使用方法是在 Activity 里面设置 StrictMode,上面的例子是打开了检查泄漏的 SQLite 对象以及 Closeable 对象

(普通 Cursor/FileInputStream 等)的功能,发现有违规情况则记录 log 并使程序强行退出。

下面是转载的原文

简介

本文介绍如何在 Android 检测 Cursor 泄漏的原理以及使用方法,还指出几种常见的出错示例。有一些泄漏在代码中难以察觉,但程序长时间运行后必然会出现异常。同时该方法同样适合于其他需要检测资源泄露的情况

 

最近发现某蔬菜手机连接程序在查询媒体存储(MediaProvider)数据库时出现严重 Cursor 泄漏现象,运行一段时间后会导致系统中所有使用到该数据库的程序无法使用。另外在工作中也常发现有些应用有 Cursor 泄漏现象,由于需要长时间运行才会出现异常,所以有的此类 bug 很长时间都没被发现。

但是一旦 Cursor 泄漏累计到一定数目(通常为数百个)必然会出现无法查询数据库的情况,只有等数据库服务所在进程死掉重启才能恢复正常。通常的出错信息如下,指出某 pid 的程序打开了 866 个 Cursor 没有关闭,导致了 exception:

3634 3644 E JavaBinder: *** Uncaught remote exception! (Exceptions are not yet supported across processes.)
3634 3644 E JavaBinder: android.database.CursorWindowAllocationException: Cursor window allocation of 2048 kb failed. # Open Cursors=866 (# cursors opened by pid 1565=866)
3634 3644 E JavaBinder: at android.database.CursorWindow.(CursorWindow.java:104)
3634 3644 E JavaBinder: at android.database.AbstractWindowedCursor.clearOrCreateWindow(AbstractWindowedCursor.java:198)
3634 3644 E JavaBinder: at android.database.sqlite.SQLiteCursor.fillWindow(SQLiteCursor.java:147)
3634 3644 E JavaBinder: at android.database.sqlite.SQLiteCursor.getCount(SQLiteCursor.java:141)
3634 3644 E JavaBinder: at android.database.CursorToBulkCursorAdaptor.getBulkCursorDescriptor(CursorToBulkCursorAdaptor.java:143)
3634 3644 E JavaBinder: at android.content.ContentProviderNative.onTransact(ContentProviderNative.java:118)
3634 3644 E JavaBinder: at android.os.Binder.execTransact(Binder.java:367)
3634 3644 E JavaBinder: at dalvik.system.NativeStart.run(Native Method)

1. Cursor 检测原理

在 Cursor 对象被 JVM 回收运行到 finalize() 方法的时候,检测 close() 方法有没有被调用,此办法在 ContentResolver 里面也得到应用。简化后的示例代码如下:

复制代码
 1 import android.database.Cursor;
 2 import android.database.CursorWrapper;
 3 import android.util.Log;
 4 
 5 public class TestCursor extends CursorWrapper {
 6     private static final String TAG = "TestCursor";
 7     private boolean mIsClosed = false;
 8     private Throwable mTrace;
 9     
10     public TestCursor(Cursor c) {
11         super(c);
12         mTrace = new Throwable("Explicit termination method 'close()' not called");
13     }
14     
15     @Override
16     public void close() {
17         mIsClosed = true;
18     }
19     
20     @Override
21     public void finalize() throws Throwable {
22         try {
23             if (mIsClosed != true) {
24                 Log.e(TAG, "Cursor leaks", mTrace);
25             }
26         } finally {
27             super.finalize();
28         }
29     }
30 }
复制代码

然后查询的时候,把 TestCursor 作为查询结果返回给 APP:

1 return new TestCursor(cursor); // cursor 是普通查询得到的结果,例如从 ContentProvider.query()

 

该方法同样适合于所有需要检测显式释放资源方法没有被调用的情形,是一种通用方法。但在 finalize() 方法里检测需要注意

优点:准确。因为该资源在 Cursor 对象被回收时仍没被释放,肯定是发生了资源泄露。

缺点:依赖于 finalize() 方法,也就依赖于 JVM 的垃圾回收策略。例如某 APP 现在有 10 个 Cursor 对象泄露,并且这 10 个对象已经不再被任何引用指向处于可回收状态,但是 JVM 可能并不会马上回收(时间不可预测),如果你现在检查不能够发现问题。另外,在某些情况下就算对象被回收 finalize() 可能也不会执行,也就是不能保证检测出所有问题。关于 finalize() 更多信息可以参考《Effective Java 2nd Edition》的 Item 7: Avoid Finalizers

2. 使用方法

对于 APP 开发人员

从 GINGERBREAD 开始 Android 就提供了 StrictMode 工具协助开发人员检查是否不小心地做了一些不该有的操作。使用方法是在 Activity 里面设置 StrictMode,下面的例子是打开了检查泄漏的 SQLite 对象以及 Closeable 对象(普通 Cursor/FileInputStream 等)的功能,发现有违规情况则记录 log 并使程序强行退出。

复制代码
 1 import android.os.StrictMode;
 2 
 3 public class TestActivity extends Activity {
 4     private static final boolean DEVELOPER_MODE = true;
 5     public void onCreate() {
 6         if (DEVELOPER_MODE) {
 7             StrictMode.setVMPolicy(new StrictMode.VMPolicy.Builder()
 8                     .detectLeakedSqlLiteObjects()
 9                     .detectLeakedClosableObjects()
10                     .penaltyLog()
11                     .penaltyDeath()
12                     .build());
13         }
14         super.onCreate();
15     }
16 }
复制代码

 

对于 framework 开发人员

如果是通过 ContentProvider 提供数据库数据,在 ContentResolver 里面已有 CloseGuard 类实行类似检测,但需要自行打开(上例也是打开 CloseGuard):

1 CloseGuard.setEnabled(true);

更值得推荐的办法是按照本文第一节中的检测原理,在 ContentResolver 内部类 CursorWrapperInner 里面加入。其他需要检测类似于资源泄漏的,同样可以使用该检测原理。

3. 容易出错的地方

忘记调用 close() 这种低级错误没什么好说的,这种应该也占不小的比例。下面说说不太明显的例子。

提前返回

有时候粗心会犯这种错误,在 close() 调用之前就 return 了,特别是函数比较大逻辑比较复杂时更容易犯错。这种情况可以通过把 close() 放在 finally 代码块解决

复制代码
1 private void method() {
2     Cursor cursor = query(); // 假设 query() 是一个查询数据库返回 Cursor 结果的函数
3     if (flag == false) {  // !!提前返回
4         return;
5     }
6     cursor.close();
7 }
复制代码

 

类的成员变量

假设类里面有一个在类全局有效的成员变量,在方法 A 获取了查询结果,后面在其他地方又获取了一次查询结果,那么第二次查询的时候就应该先把前面一个 Cursor 对象关闭。

复制代码
 1 public class TestCursor {
 2     private Cursor mCursor;
 3 
 4     private void methodA() {
 5         mCursor = query();
 6     }
 7 
 8     private void methodB() {
 9         // !!必须先关闭上一个 cursor 对象
10         mCursor = query();
11     }
12 }
复制代码

注意:曾经遇到过有人对 mCursor 感到疑惑,明明是同一个变量为什么还需要先关闭?首先 mCursor 是一个 Cursor 对象的引用,在 methodA 时 mCursor 指向了 query() 返回的一个 Cursor 对象 1;在 methodB() 时它又指向了返回的另外一个 Cursor 对象 2。在指向 Cursor 对象 2 之前必须先关闭 Cursor 对象 1,否则就出现了 Cursor 对象 1 在 finalize() 之前没有调用 close() 的情况。

异常处理

打开和关闭 Cursor 之间的代码出现 exception,导致没有跑到关闭的地方:

复制代码
1 try {
2     Cursor cursor = query();
3     // 中间省略某些出现异常的代码
4     cursor.close();
5 } catch (Exception e) {
6     // !!出现异常没跑到 cursor.close()
7 }
复制代码

这种情况应该把 close() 放到 finally 代码块里面:

复制代码
 1 Cursor cursor = null;
 2 try {
 3     cursor = query();
 4     // 中间省略某些出现异常的代码
 5 } catch (Exception e) {
 6     // 出现异常
 7 } finally {
 8     if (cursor != null)
 9         cursor.close();
10 }
复制代码

4. 总结思考

在 finalize() 里面检测是可行的,且基本可以满足需要。针对 finalize() 执行时间不确定以及可能不执行的问题,可以通过记录目前打开没关闭的 Cursor 数量来部分解决,超过一定数目发出警告,两种手段相结合。

还有没有其他检测办法呢?有,在 Cursor 构造方法以及 close() 方法添加 log,运行一段时间后检查 log 看哪个地方没有关闭。简化代码如下:

复制代码
 1 import android.database.Cursor;
 2 import android.database.CursorWrapper;
 3 import android.util.Log;
 4 
 5 public class TestCursor extends CursorWrapper {
 6     private static final String TAG = "TestCursor";
 7     private Throwable mTrace;
 8     
 9     public TestCursor(Cursor c) {
10         super(c);
11         mTrace = new Throwable("cusor opened here");
12         Log.d(TAG, "Cursor " + this.hashCode() + " opened, stacktrace is: ", mTrace);
13     }
14     
15     @Override
16     public void close() {
17         mIsClosed = true;
18         Log.d(TAG, "Cursor " + this.hashCode() + " closed.");
19     }
20 }
复制代码

检查时看某个 hashCode() 的 Cursor 有没有调用过 close() 方法,没有的话说明资源有泄露。这种方法优点是同样准确,且更可靠。缺点是需要检查大量 log,且打开/关闭的地方可能相距较远,如果不写个小脚本分析人工看的话会比较痛苦;另外必须 APP 完全退出后才能检查,因为后台运行时某些 Cursor 还在正常使用。

转载请注明出处:http://www.cnblogs.com/imouto/archive/2013/01/14/how-to-detect-leaked-cursor.html

本文外部镜像:http://oteku.blogspot.com/2013/01/how-to-detect-android-cursor-leak-cn.html

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/191717.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • Android Activity 生命周期

    Android Activity 生命周期

    2021年8月23日
    90
  • PLSQL Developer连接Oracle11g 64位数据库配置详解

    PLSQL Developer连接Oracle11g 64位数据库配置详解最近换了台64bit的电脑,所以oracle数据库也跟着换成了64bit的,不过问题也随之产生,由于plsqldeveloper暂时没有64bit版本的,所以无法连接到64bit的oracle上,经过一番折腾,终于成功连接到数据库上,现记录下配置过程,以便查看。

    2022年5月26日
    52
  • HTTP.sys远程代码执行漏洞修复

    HTTP.sys远程代码执行漏洞修复1.漏洞描述Http.sys是MicrosoftWindows处理HTTP请求的内核驱动程序。HTTP.sys会错误解析某些特殊构造的HTTP请求,导致远程代码执行漏洞。成功利用此漏洞后,攻击者可在System帐户上下文中执行任意代码。由于此漏洞存在于内核驱动程序中,攻击者也可以远程导致操作系统蓝屏。此次受影响的系统中,Windows7、Windows8、WindowsServer2008R2和WindowsServer2012所带的HTTP.sys驱动均存在一个远程代码执行漏洞,远程攻击者可以通

    2022年7月18日
    14
  • 因果图分析法[通俗易懂]

    因果图分析法[通俗易懂]目录一、因果图法1.理解二、因果图需要掌握的基本知识1.关系2.约束3.输出条件的约束4.输出条件的约束5.原因和结果表示6.中间节点三、因果图设计测试用例的步骤四、优缺点1.优点2.缺点五、实例1.案例2.分析案例六、为什么要有中间节点1.无中间节点因果图2.有中间节点因果图一、因果图法1.理解因果图是一种简化了的逻辑图,能直观的表明程序输入条件(原因)和输出动作(结果)之间的相互关系; 因果图法是借助图形来设计测试

    2022年8月14日
    1
  • java中的static关键字的作用?

    java中的static关键字的作用?是静态修饰符,什么叫静态修饰符呢?大家都知道,在程序中任何变量或者代码都是在编译时由系统自动分配内存来存储的,而所谓静态就是指在编译后所分配的内存会一直存在,直到程序退出内存才会释放这个空间,也就是只要程序在运行,那么这块内存就会一直存在。这样做有什么意义呢?在Java程序里面,所有的东西都是对象,而对象的抽象就是类,对于一个类而言,如果要使用他的成员,那么普通情况下必须先实例化对象后,通过对象

    2022年7月8日
    19
  • J1939广播DM1报文

    J1939广播DM1报文一、DM1报文1,SAEJ1939-21(参考5.2)对CANID进行了重新划分,加上8个字节的数据域,构成了J1939的协议数据单元(ProtocolDataUnit,PDU)。SAEJ1939-73(参考5.7.1)中定义了DM1的优先级为6,PGN(参数组数编号)为65226(00FECA),所以源地址为0x41的DM1ID为18FECA41。2,假设源地址为0x41的节点,存在两个现行故障,故障的SPN,FMI分别为(521132,1),(521008,3),按照DTC结构

    2022年6月2日
    208

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号