Sqlite3内存调试
Posted 林多
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Sqlite3内存调试相关的知识,希望对你有一定的参考价值。
Sqlite3内存调式
- 基本上来说Sliqte3提供的接口,只要正确操作,是不会发生内存泄漏的问题。它有一套严格的内存理论,以及实现机制。这里主要讨论,如何进行内存方面的调式、确认。
Sqlite3动态内存
- 查看sqllite3当前持有的动态内存大小(byte)。该接口通过获取SQLITE_STATUS_MEMORY_USED状态值实现。大概原理为,sqlite3在申请或释放动态内存时,会将SQLITE_STATUS_MEMORY_USED对应的状态值做加或减去分配的bytpe的操作。
// 接口
sqlite3_int64 sqlite3_memory_used(void);
// 接口的实现
// 该接口会返回sqlite3持有的动态分配的内存大小。
sqlite3_int64 sqlite3_memory_used(void)
int n, mx;
sqlite3_int64 res;
sqlite3_status(SQLITE_STATUS_MEMORY_USED, &n, &mx, 0);
res = (sqlite3_int64)n; /* Work around bug in Borland C. Ticket #3216 */
return res;
// sqlite3内部实现逻辑
/*
** Free memory previously obtained from sqlite3Malloc().
*/
void sqlite3_free(void *p)
// 省略
// 记录释放的内存字节数(负数)
sqlite3StatusAdd(SQLITE_STATUS_MEMORY_USED, - sqlite3MallocSize(p));
/*
** Do a memory allocation with statistics and alarms. Assume the
** lock is already held.
*/
static int mallocWithAlarm(int n, void **pp)
// 记录申请的内存szie(正数)
nFull = sqlite3MallocSize(p);
sqlite3StatusAdd(SQLITE_STATUS_MEMORY_USED, nFull);
- 获取sqlite3内部状态接口,第一个in参数表示状态类型,第二个out参数表示状态的当前值,第三个output参数为状态记录的最高值,第四个参数为ture时表示该函数后清空记录最高值。
int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag);
- 可用的状态值
// 当前内存
#define SQLITE_STATUS_MEMORY_USED 0
// 页内存
#define SQLITE_STATUS_PAGECACHE_USED 1
#define SQLITE_STATUS_PAGECACHE_OVERFLOW 2
#define SQLITE_STATUS_SCRATCH_USED 3
#define SQLITE_STATUS_SCRATCH_OVERFLOW 4
#define SQLITE_STATUS_MALLOC_SIZE 5
#define SQLITE_STATUS_PARSER_STACK 6
#define SQLITE_STATUS_PAGECACHE_SIZE 7
#define SQLITE_STATUS_SCRATCH_SIZE 8
// 执行过malloc的数量(malloc时+1,free时-1)
#define SQLITE_STATUS_MALLOC_COUNT 9
- 修改sqlite代码,检查是否存在内存泄漏。修改sqlite3StatusAdd函数,让其在执行时,输出分配的内存的size。同时修改sqlite3MemSize和sqlite3MemFree函数,让其输出指针的地址。例:
// 输出内存增加/释放的size
void sqlite3StatusAdd(int op, int N)
if (SQLITE_STATUS_MEMORY_USED == op)
printf("sqlite3StatusAdd memory change [%d]", N);
// ....
// 一般来讲,内存分配、释放都会调用该函数,或者size,然后使用sqlite3StatusAdd记录。所以可以加在该函数中。
static int sqlite3MemSize(void *pPrior)
#ifdef SQLITE_MALLOCSIZE
return pPrior ? (int)SQLITE_MALLOCSIZE(pPrior) : 0;
#else
sqlite3_int64 *p;
if( pPrior==0 ) return 0;
p = (sqlite3_int64*)pPrior;
p--;
printf("sqlite3MemSize buffer addr[%p]", p);
return (int)p[0];
#endif
// 看一下释放的内存的地址。
static void sqlite3MemFree(void *pPrior)
#ifdef SQLITE_MALLOCSIZE
SQLITE_FREE(pPrior);
#else
sqlite3_int64 *p = (sqlite3_int64*)pPrior;
assert( pPrior!=0 );
p--;
printf("sqlite3MemFree addr[%p]", p);
SQLITE_FREE(p);
#endif
-
通过在源码中,追加输出信息,可以更直接的观察sqlite分配的内存信息。
-
另外,也可以使用varglind进行内存调式。
关于Sqlite3内存无法释放的问题
- 近期遇到了一个Sqlite3内存无法释放的问题,通过sqlite3_finalize函数释放后,查看进程的内存仍然没有降低。关于这个问题,通过分析后,最终发现sqlite3对于所有动态申请的内存,都调用了free操作。而问题的真因在于,运行进程的 系统上,对于malloc的内存,free后不会立即释放导致(关于该原因及解决方法,网上有一些文章,可自行百度)。
以上是关于Sqlite3内存调试的主要内容,如果未能解决你的问题,请参考以下文章