我有一个问题,我想在SQLite数据库中插入7000行,但当我到达第6000行时,我的应用程序崩溃,没有错误。
我使用了一个分析器,显然问题是我的iPad使用了RAM(当应用程序分配了435MB的RAM时崩溃)。
所以我的问题是如何在插入期间管理内存? (是的,我需要在本地拥有这些数据,因为我的应用程序需要在断开连接模式下工作)。
以下是我用于在表中插入行的代码:
-(void)MultiInsertFamille:(NSArray *)categories{
sqlite3_stmt *stmt=nil;
sqlite3 *bdd;
NSString *database = [[NSHomeDirectory() stringByAppendingPathComponent:@"Documents"] stringByAppendingPathComponent:@"myBDD.sqlite"];
if (sqlite3_open([database UTF8String], &bdd) == SQLITE_OK)
{
sqlite3_exec(bdd, "BEGIN", 0, 0, 0);
const char *sqlstatement="insert into Famille values(?,?,?,?,?,?,?)";
if(sqlite3_prepare_v2(bdd,sqlstatement , -1, &stmt, NULL)==SQLITE_OK)
{
int hasError= 0;
int i = 0;
for(NSString *path in categories)
{
i++;
NSString *nameFile = [[path componentsSeparatedByString: @"."] objectAtIndex:0];
XMLParserFamille *fa = [[XMLParserFamille alloc] initXMLParserFamille:nameFile parseError:nil];
FamilleData *fam = fa.famille;
[fa release];
if (fam.champ_Recherche)
sqlite3_bind_text(stmt, 1, [fam.champ_Recherche cStringUsingEncoding:NSUTF8StringEncoding], -1, SQLITE_TRANSIENT);
else
sqlite3_bind_text(stmt, 1, "NULL", -1, SQLITE_TRANSIENT);
NSString *pathImTh = @"";
for (Attribut *att in fam.Attributs)
{
if ([att.name isEqualToString:@"ProductThumbnail"])
{
pathImTh = att.value;
break;
}
}
if (pathImTh)
sqlite3_bind_text(stmt, 2, [pathImTh cStringUsingEncoding:NSUTF8StringEncoding], -1, SQLITE_TRANSIENT);
else
sqlite3_bind_text(stmt, 2, "NULL", -1, SQLITE_TRANSIENT);
if (fam.nom)
sqlite3_bind_text(stmt, 3, [fam.nom cStringUsingEncoding:NSUTF8StringEncoding], -1, SQLITE_TRANSIENT);
else
sqlite3_bind_text(stmt, 3, "NULL", -1, SQLITE_TRANSIENT);
if (fam.ordre)
sqlite3_bind_int(stmt, 4, [fam.ordre intValue]);
else
sqlite3_bind_int(stmt, 4, 0);
if (fam.uid)
sqlite3_bind_text(stmt, 5, [fam.uid cStringUsingEncoding:NSUTF8StringEncoding], -1, SQLITE_TRANSIENT);
else
sqlite3_bind_text(stmt, 5, "NULL", -1, SQLITE_TRANSIENT);
if (fam.uid_Categorie)
sqlite3_bind_text(stmt, 6, [fam.uid_Categorie cStringUsingEncoding:NSUTF8StringEncoding], -1, SQLITE_TRANSIENT);
else
sqlite3_bind_text(stmt, 6, "NULL", -1, SQLITE_TRANSIENT);
if (fam.xmlErrone)
sqlite3_bind_int(stmt, 7, [fam.xmlErrone intValue]);
else
sqlite3_bind_int(stmt, 7, 0);
if(sqlite3_step(stmt)==SQLITE_DONE)
{
NSLog(@"OK");
}
else
{
NSLog(@"sqlite3_step error famille: '%s'", sqlite3_errmsg(bdd));
hasError= 1;
}
sqlite3_reset(stmt);
if (i==5500)
break;
}
//if( hasError == 0 ) {
sqlite3_exec(bdd, "COMMIT", 0, 0, 0);
//}
//else {
// sqlite3_exec(bdd, "ROLLBACK", 0, 0, 0);
//}
}
}
sqlite3_close(bdd);}
答案 0 :(得分:2)
您可以尝试执行较小的事务,例如每1000行开始/提交一次。
这样的事情可能有所帮助:
NSInteger rowsProcessed = 0;
for(NSString *path in categories)
{
if (rowsProcessed == 0)
{
sqlite3_exec(bdd, "BEGIN", 0, 0, 0);
}
if (rowsProcessed++ > 1000)
{
sqlite3_exec(bdd, "COMMIT", 0, 0, 0);
rowsProcessed = 0;
}
...
// your inserts here
...
}
if (rowsProcessed != 0)
{
sqlite3_exec(bdd, "COMMIT", 0, 0, 0);
}
提交没有提交的变通方法(可能会影响性能,因此如果你完全删除了begin / commit,sqlite会添加隐式事务):
答案 1 :(得分:0)
循环中可能会创建很多临时对象(例如字符串处理)。
你可以尝试将你的东西放入自动释放池块中,所以 临时对象将在每个循环结束时释放。
for(NSString *path in categories) {
@autoreleasepool {
your stuff here ..
}
}