程式進程記憶體洩漏檢測報告:
Detected memory leaks!
Dumping objects ->
{814} normal block at 0x0370AFD0, 40 bytes long.
Data: 74 61 62 6C 65 20 54 61 62 6C 65 5F 53 74 72 61 (table Table_Str)
Object dump complete.
洩漏內容正是建表 SQL 字串片段,提示與 sqlite3_exec 錯誤處理有關。
if (result == SQLITE_OK) {
char *errmsg = NULL;
int nError = sqlite3_exec(
m_sqlite3DB,
"create table Table_StrangeWords( ID integer primary key autoincrement, name nvarchar(32) ,)",
NULL, NULL, &errmsg );
if (nError != SQLITE_OK) {
ATLTRACE("建立表失敗,錯誤碼:%d,錯誤原因:%s\n", result, errmsg);
}
// 缺少釋放 errmsg!
}
追蹤 SQLite 原始碼(sqlite3_exec → sqlite3ApiExit):
if (rc != SQLITE_OK && rc == sqlite3_errcode(db) && pzErrMsg) {
int nErrMsg = 1 + strlen(sqlite3_errmsg(db));
*pzErrMsg = sqlite3_malloc(nErrMsg); // 內部分配緩衝區
if (*pzErrMsg) {
memcpy(*pzErrMsg, sqlite3_errmsg(db), nErrMsg);
}
}
關鍵點:SQLite 以 sqlite3_malloc 分配錯誤訊息緩衡區,**呼叫端負責釋放**,且**必須用 sqlite3_free**,不能用 delete 或 free。
if (result == SQLITE_OK) {
char *errmsg = NULL;
int nError = sqlite3_exec(
m_sqlite3DB,
"create table Table_StrangeWords( ID integer primary key autoincrement, name nvarchar(32) ,)",
NULL, NULL, &errmsg );
if (nError != SQLITE_OK) {
ATLTRACE("建立表失敗,錯誤碼:%d,錯誤原因:%s\n", result, errmsg);
}
// 正確釋放
if (errmsg != NULL) {
sqlite3_free(errmsg); // 必須用 sqlite3_free
}
}
sqlite3_malloc/sqlite3_realloc 分配的記憶體,必須配對 sqlite3_free 釋放**errmsg 即使執行成功(SQLITE_OK)也可能被分配(視版本),統一在最後檢查並釋放同樣適用於 sqlite3_get_table、sqlite3_prepare 等回傳緩衝區的 API。養成「用完即釋、成對出現」習慣,避免 C/C++ 手動記憶體管理陷阱。