我写了一个sqlite C程序的例子,它尝试创建一个DB及其表并连续插入其表。但我的程序没有关闭它打开的数据库,它也有内存泄漏。 我找不到自己的错误。 这是我的C代码:
#include <stdio.h>
#include <stdlib.h>
#include <sqlite3.h>
#include <string.h>
#include <time.h>
#define SQLITE_MAIN_BASE "/var/"
#define SQLITE_DEVLOG_BASE "./"
#define Create_All_Database_Error 1
void addlog(const char * logtext,const char *logpath)
{
struct tm *timeinfo;
time_t rawtime;
if (logpath != NULL )
{
if (strlen(logpath) > 4)
{
FILE *Lfile;
Lfile = fopen(logpath,"a");
if (Lfile)
{
char cur_dtime[50];
time ( &rawtime );
timeinfo = localtime (&rawtime);
strcpy(cur_dtime,asctime(timeinfo));
cur_dtime[strlen(cur_dtime)-1] = '\0';
fputs(cur_dtime,Lfile);
fputs(" :: ",Lfile);
fputs(logtext,Lfile);
fputs("\n",Lfile);
fclose(Lfile);
}
else
{
fprintf(stderr,"can not open log file %s\n",logpath);
}
}
}
}
MySqlite_close(sqlite3 *db)
{
int i=0,
rc=0;
rc=sqlite3_close(db);
while(rc != SQLITE_OK)
{
printf("yet closing\n");
if (rc == SQLITE_BUSY)
{
printf("it is busy\n");
i++;
if ( i > 10 )
{
return rc;
}
}
sleep(1);
rc=sqlite3_close(db);
}
printf("2closeeeeeee\n\n");
return 0;
}
int MySqlite_Exec(const char *dbname,const char *query,sqlite3_stmt **retStmt,const char *queryTail2,const char *logpath,int logfd,int mode)
{
sqlite3 *db;
char logmessage[1500];
char dbfilepath[150];
int rc=0;
retStmt=NULL;
sprintf(dbfilepath,"%s%s",SQLITE_DEVLOG_BASE,dbname);
fprintf(stdout,"%s\n",query);
// fprintf(stdout,"%s\n",dbfilepath);
rc = sqlite3_open(dbfilepath, &db);
// if( rc )
while(sqlite3_open(dbfilepath, &db))
{
sprintf(logmessage,"1Error on \"%s\" : %u %s ",query,sqlite3_errcode(db), sqlite3_errmsg(db));
printf("%s\n",logmessage);
// addlog(logmessage,logpath);
// printf("1\n");
sleep(10);
MySqlite_close(db);
// return sqlite3_errcode(db);
return 0;
}
printf("10\n");
if( sqlite3_prepare_v2(db, query, strlen(query)+1, retStmt,NULL) != SQLITE_OK )
{
sprintf(logmessage,"2Error on \"%s\" : %u %s ",query,sqlite3_errcode(db), sqlite3_errmsg(db));
printf("%s\n",logmessage);
// addlog(logmessage,logpath);
while(sqlite3_prepare_v2(db, query, strlen(query)+1, retStmt,NULL) == SQLITE_BUSY)
{
sprintf(logmessage,"2Error on \"%s\" : %u %s ",query,sqlite3_errcode(db), sqlite3_errmsg(db));
printf("%s\n",logmessage);
// addlog(logmessage,logpath);
sleep(1);
}
}
printf("12\n");
if (mode==0)
{
printf("222\n");
if (sqlite3_step(*retStmt) != SQLITE_DONE)
{
sprintf(logmessage,"3Error on \"%s\" : %u %s ",query,sqlite3_errcode(db), sqlite3_errmsg(db));
printf("%s\n",logmessage);
}
if ( *retStmt != NULL )
{
printf("retStmt is not NULL\n");
sqlite3_step(*retStmt);
while(sqlite3_finalize(*retStmt)!=SQLITE_OK)
{
sprintf(logmessage,"20Error on : %u %s ",sqlite3_errcode(db), sqlite3_errmsg(db));
printf("%s\n",logmessage);
printf("finilized NOT ok\n");
sleep(1);
}
printf("finilized ok\n");
// sqlite3_exec(db, "COMMIT", NULL, NULL, NULL);
}
else
{
printf("retStmt is NULL\n");
}
MySqlite_close(db);
}
return 0;
}
int Create_SqltDB(void)
{
char hostip[20],
LOG_FILE[100],
query[1000],
dbfilepath[100],
logmessage[1500];
int result=0;
const char *queryTail;
sqlite3_stmt *retStmt;
sprintf(LOG_FILE,"/var/log/Emain.log");
sprintf(query,"create table if not exists lastuptime(row integer primary key not NULL,microupdatetime double default 0 not NULL,time double default 0 not NULL);");
if (MySqlite_Exec("lastuptime",query,&retStmt,queryTail,LOG_FILE,2,0))
{
return Create_All_Database_Error;
}
int i=0;
for (i=0; i<1000000;i++)
{
sprintf(query,"insert into lastuptime(microupdatetime,time) values (%i,%i);",i,i);
if (MySqlite_Exec("lastuptime",query,&retStmt,queryTail,LOG_FILE,2,0))
{
return Create_All_Database_Error;
}
}
sprintf(query,"select * from lastuptime;");
if (MySqlite_Exec("lastuptime",query,&retStmt,queryTail,LOG_FILE,2,1))
{
return Create_All_Database_Error;
}
do
{
result = sqlite3_step (retStmt) ;
if (result == SQLITE_ROW) /* can read data */
{
printf(" %d \t|\t %f \t|\t '%f' \n",\
sqlite3_column_int(retStmt,0),\
sqlite3_column_double(retStmt,1),\
sqlite3_column_double(retStmt,2)) ;
}
else
{
printf("no data\n");
}
} while (result == SQLITE_ROW) ;
}
int main()
{
Create_SqltDB();
return 0;
}
这是我的日志:
create table if not exists lastuptime(row integer primary key not NULL,microupdatetime double default 0 not NULL,time double default 0 not NULL);
10
12
222
retStmt is not NULL
finilized ok
2closeeeeeee
insert into lastuptime(microupdatetime,time) values (0,0);
10
12
222
retStmt is not NULL
finilized ok
2closeeeeeee
insert into lastuptime(microupdatetime,time) values (1,1);
10
12
222
retStmt is not NULL
finilized ok
2closeeeeeee
..
..
..
..
.
insert into lastuptime(microupdatetime,time) values (1017,1017);
10
12
222
retStmt is not NULL
finilized ok
2closeeeeeee
insert into lastuptime(microupdatetime,time) values (1018,1018);
10
12
222
3Error on "insert into lastuptime(microupdatetime,time) values (1018,1018);" : 14 unable to open database file
retStmt is not NULL
20Error on : 14 unable to open database file
finilized NOT ok
20Error on : 14 unable to open database file
finilized NOT ok
20Error on : 14 unable to open database file
finilized NOT ok
20Error on : 14 unable to open database file
finilized NOT ok
20Error on : 14 unable to open database file
finilized NOT ok
我用lsof和htop检查了我的运行过程,找出它打开的文件和内存泄漏。 谢谢你的帮助
答案 0 :(得分:2)
您的代码的以下片段看起来很可疑,因为在没有介入关闭的情况下进行多次公开调用。
rc = sqlite3_open(dbfilepath, &db);
// if( rc )
while(sqlite3_open(dbfilepath, &db))
...
documentation声明如下:
打开时是否发生错误,资源相关联 应该通过传递它来释放数据库连接句柄 不再需要sqlite3_close()时。
答案 1 :(得分:0)
根据这个页面它是故意的。如果数据库发生了某些事情,则不会关闭文件句柄。 根据我的经验,如果不修改数据库,文件句柄将始终关闭。