sqlite3 内存占用不断增加的问题

1 背景

  1. 嵌入式项目,故选用轻量级数据库 sqlite3;
  2. 通过 sqlite3 存储日志,日志数量较多,数据库文件大于500M;
  3. 嵌入式系统内存400M左右。

2 问题


在集成过程中出现如下问题:

  1. 通过 sqlite3_exec 函数不断往数据库中插入日志,内存占用不断增加;
  2. 通过 select count(*) from table_name获取日志的条数,内存迅速增大,增加的内存约等于数据库文件的大小。

开始一直以为是内存泄露了,不断排查程序,没有发现异常。

3 排查


针对问题1:

  1. 在网上有说是因为在执行 sqlite3_exec 之后没有通过 sqlite3_free 释放错误信息指针的原因,确实我当时也没加这个,所以加上这个释放函数,但是也并没有解决内存增加的问题,代码如下:

    int ret = sqlite3_exec(pSqliteDb, pSqlBuf, NULL, NULL, &pErrmsg);
    if (DB_OK != ret)
    {
    	PrintWarn("sqlite3 exec error, ret: %d, errmsg: %s\n", ret, pErrmsg);
    	sqlite3_free(pErrmsg);
    }
    
  2. 也有说通过 sqlite3_get_table 和 sqlite3_free_table 函数组合去实现可以避免内存增加的问题,但是我用这两个函数去替换也没起到效果。

针对问题2:

  1. 在网上有查到说通过 count(0) 和 count(1) 替换 count(*),如下:

    select count(0) frome table_name
    select count(1) frome table_name
    

    无法解决。

  2. 也有说通过增加条件进行查找,如下:

    selcet count(*) from table_name where ID > 0;	/* ID是我数据库表中的主键,自动增加的数值 */
    

    也无法解决。

4 原因


后面通过 Free 命令发现其实内存增加是 Linux 的缓存在不断增加,实际程序使用的内存是不会一直增加的。这是由于 Linux 为了提高数据库的读写速度,会在读取数据库时,并且内存充足的情况下,将数据库的数据读到缓存中,所以会导致内存占用瞬间增加很多;而在插入数据时,也会将新插入的数据存到缓存中,从而导致内存占用不断增加。

如下图缓存占用的内存量就很大:
在这里插入图片描述

上述所说的这些其实是 Linux 内存管理机制引起的,其实并不会导致内存不够用的情况发生,因为在进程需要内存时,Linux 会释放掉部分缓存给进程使用,出于谨慎考虑,我又进行了如下测试进行验证:

  1. 设备内存400多M,我使用500M的数据库,直接去获取数据库的日志条数,不会导致内存崩溃,占用缓存大约200M;
  2. 写测试程序不断分配内存,将设备的内存占用到剩20M,然后去获取数据库的日志条数,不会导致内存崩溃,占用缓存少数,但是获取日志条数的时间增加比较多;
  3. 写测试程序不断分配内存,将设备的内存占用到剩下5M,然后不断插入日志到数据库,不会导致内存崩溃;
  4. 将数据库文件控制在350M左右,然后获取日志条数,使其占掉内存的大多数,接着写测试程序去不断分配内存,在内存被占满之后,会释放掉部分缓存给测试程序去使用;
  5. 通过测试读写大文件,也会出现跟数据库一样的问题。

5 解决方法


由上述测试结果可知,sqlite3 数据库的读写并不会导致内存泄露,而读写数据导致的内存占用不断增加,并不会引起内存问题,也不会引起内存不够用导致进程崩溃的问题,只是 Linux 内部的机制引起,通过内存占用增加去提高文件读写的效率,这无可厚非,在内存不够时,会自动去释放该部分的缓存,并不会导致内存崩溃,故不需要自己去处理。

如果非要去人为干预(不建议),也是有办法的,可以通过如下方法手动释放缓存:

Linux 释放内存的命令:

echo 1 > /proc/sys/vm/drop_caches

drop_caches 的值可以是 0-3 之间的数字,代表不同的含义:

  • 0:不释放(系统默认值)
  • 1:释放页缓存
  • 2:释放 dentries 和 inodes
  • 3:释放所有缓存

如果我们需要释放所有缓存,就输入下面的命令:

echo 3 > /proc/sys/vm/drop_caches

在释放缓存前需要先执行 sync,将缓存同步到文件中:

sync

释放完内存后改回去让系统重新自动分配内存:

echo 0 > /proc/sys/vm/drop_caches

总的步骤就是:

sync
echo 1 > /proc/sys/vm/drop_caches
echo 0 > /proc/sys/vm/drop_caches
  • 5
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

半砖

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值