【发布时间】:2014-09-05 01:11:08
【问题描述】:
我在长时间运行一个简单的单线程 C++ 程序时遇到内存使用问题(比如通宵运行)。该程序使用 SQLite3 API 打开一个数据库并在其中循环写入一些数据。我在两台不同的机器上运行该程序:一台桌面 Ubuntu Linux 和一台运行定制 Linux 的基于 ARM 的嵌入式设备。 在这两种情况下,我都得到了相同的结果:内存逐渐消耗,并且在应用程序运行时没有释放。我正在使用在后台运行的简单 bash 脚本检查内存使用情况:
while true;
do free -m;
sleep 2;
done
需要注意的是,我也在使用 SQLite 提供的 API 监控内存使用情况:
sqlite3_memory_used()
API 报告的已用内存量相当稳定,但“free -m”报告不同并逐渐增加。
SQLite 源代码使用以下标志编译:
SQLITE_DEFAULT_TEMP_CACHE_SIZE=3
SQLITE_DEFAULT_WAL_AUTOCHECKPOINT=2
SQLITE_MAX_MMAP_SIZE=2048
SQLITE_ENABLE_MEMSYS5
SQLITE_ENABLE_MEMORY_MANAGEMENT
SQLITE_DEFAULT_CACHE_SIZE=3
SQLITE_DEFAULT_AUTOVACUUM=1
SQLITE_DEFAULT_PAGE_SIZE=512
请注意,在这个阶段我并不关心速度,但我主要关心的是内存使用,所以我设置参数的方式是让最少的数据缓存在内存中并尽快将它们推送到磁盘。
我还在每次迭代中使用“PRAGMA shrink_memory”。
为了尽量减少动态内存分配,我还为以下内存类型提供了静态数组:
SQLITE_CONFIG_HEAP
SQLITE_CONFIG_SCRATCH
SQLITE_CONFIG_PAGECACHE
写入数据库的代码 sn-p 如下所示:
char SQL_Statement[100]={0};
char *ErrMsg = 0;
for (int i = 0; i < 1000000; i++)
{
sprintf(SQL_Statement, "INSERT INTO PointValue (TimeStamp, BlockId, PointId, Value) VALUES (%f, %d, %d, %d);",TimeStamp_ ,BlockId_, PointId_, Value_ );
check = sqlite3_exec(MyDB, SQL_Statement, callback, (void*)data, &ErrMsg);
sqlite3_free(ErrMsg);
}
【问题讨论】:
-
char SQL_Statement[100]={0};看看sprintf,如果你声明一个只有 100 个字符的数组,你就在刀刃上取得平衡。如果您通过声明这么小的数量来创建内存覆盖,我不会感到惊讶。 -
应该是“少量”。
-
感谢@PaulMcKenzie 的评论。我检查了生成的字符串的大小并确认它低于 100(它是 85 个字符)。所有参数都是固定值,不会增长。
-
我不认为你可以用可调试的 sqlite 源代码在一夜之间让 Valgrind 松动?我想这会很有启发性。您是否体验过与 ARM 装备相似的关闭特性?
-
有证据表明内存没有被SQLite使用。此外,该内存是由该进程消耗还是由文件缓存消耗?