我在运行一个简单的单线程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
请注意,在这个阶段我并不关心速度,但我主要担心的是内存使用情况,因此我设置参数的方式是将最小数据缓存在内存中并尽快将它们推送到磁盘。 / p>
我还在每次迭代中使用“PRAGMA shrink_memory”。
为了最小化动态内存分配,我还为以下内存类型提供了静态数组:
SQLITE_CONFIG_HEAP
SQLITE_CONFIG_SCRATCH
SQLITE_CONFIG_PAGECACHE
写入数据库的代码片段如下所示:
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);
}
答案 0 :(得分:1)
sqlite3_exec 的最后一个参数只在初始化时调用sqlite3_malloc并且需要被释放时才会设置错误,但是当没有错误被设置为NULL时,可能是个问题使用NULL变量调用sqlite3_free。尝试添加条件:
if (ErrMsg != nullptr) // if C++11 or NULL o 0 if C++98
sqlite3_free(ErrMsg);
查看网址:http://www.sqlite.org/c3ref/exec.html
作为Sqlite3文档状态,传递给回调的内存不需要任何空闲调用,所有内容都将自动释放并且在sqlite3_step内部调用sqlite3_step()之后无效,因此,如果需要将值保存在对于后者使用的回调,你需要复制它,指针在下一个回调调用或之后执行的代码中变为无效。
答案 1 :(得分:1)
感谢大家的回答和评论。 确认内存被linux页面缓存占用,这很好,因为Linux希望能够处理它并在另一个应用程序需要更多内存时释放不必要的页面。 只需使用一个简单的命令:
cat /proc/meminfo