1

I'm going through a rigorous memory based issue while iterating over a loop performing bulk insertion in SQLite database .

I'm quiet sure this is memory concerned and I'm unable to point out the variable causing problems. I have released everything allocated as far as I can check.

There are no memory leaks upto this point analyzed through instruments. The snippet of code is as follows :

int m=0;

while ([arrData count]!=0) {

if (newQuery) {

    exeQuery = query;
    newQuery = false;

}
else 
{
    exeQuery=[exeQuery stringByAppendingFormat:@" UNION"];
}

NSMutableDictionary *data = [[NSMutableDictionary alloc] initWithDictionary:[arrData objectAtIndex:0]];

[data removeObjectForKey:@"statement"];
[data removeObjectForKey:@"datetime_stamp"];

NSString *strVal=@"";
NSString *_value=@"";

int i=0;
    for(;i<[keys  count]-1;i++)
    {
        if(_value==nil || _value==NULL){
            _value=@"";
        }

        _value=[NSString stringWithFormat:@"%@",[data objectForKey:[keys objectAtIndex:i]]];
        _value=[_value stringByReplacingOccurrencesOfString:@"'" withString:@"''"];

        strVal=[strVal stringByAppendingFormat:@"'%@',",_value];

    }

if(_value==nil || _value==NULL){
    _value=@"";
}

_value=[NSString stringWithFormat:@"%@",[data objectForKey:[keys objectAtIndex:i]]];
_value=[_value stringByReplacingOccurrencesOfString:@"'" withString:@"''"];

strVal=[strVal stringByAppendingFormat:@"'%@'",_value];


exeQuery=[exeQuery stringByAppendingFormat:@" SELECT %@",strVal];


if (m!=0 && m%499==0) {

    [DataSource executeQuery:exeQuery];

    //db.execute(exeQuery);
    newQuery = true;
}

[data release];

[arrData removeObjectAtIndex:0];

m++;
}

for (;m<locations_length; m++) {

if (newQuery) {

    exeQuery = query;
    newQuery = false;

}
else 
{
    exeQuery=[exeQuery stringByAppendingFormat:@" UNION"];
}

NSMutableDictionary *data = [[NSMutableDictionary alloc] initWithDictionary:[arrData objectAtIndex:m]];

[data removeObjectForKey:@"statement"];
[data removeObjectForKey:@"datetime_stamp"];

NSString *strVal=@"";
NSString *_value=@"";

int i=0;
    for(;i<[keys  count]-1;i++)
    {
        if(_value==nil || _value==NULL){
            _value=@"";
        }

        _value=[NSString stringWithFormat:@"%@",[data objectForKey:[keys objectAtIndex:i]]];
        _value=[_value stringByReplacingOccurrencesOfString:@"'" withString:@"''"];

        strVal=[strVal stringByAppendingFormat:@"'%@',",_value];

    }

if(_value==nil || _value==NULL){
    _value=@"";
}

_value=[NSString stringWithFormat:@"%@",[data objectForKey:[keys objectAtIndex:i]]];
_value=[_value stringByReplacingOccurrencesOfString:@"'" withString:@"''"];

strVal=[strVal stringByAppendingFormat:@"'%@'",_value];


exeQuery=[exeQuery stringByAppendingFormat:@" SELECT %@",strVal];


if (m!=0 && m%499==0) {

    [DataSource executeQuery:exeQuery];

    //db.execute(exeQuery);
    newQuery = true;
}

[data release];
}

Any help is greatly appreciated. Plz join hands.. !

Thanks in advance.

Faery
  • 4,552
  • 10
  • 50
  • 92
Raj
  • 1,213
  • 2
  • 16
  • 34
  • When I had memory problems in my app, that I couldn't solve for a long time, I just tried to switch whole project to ARC and it helped. (XCode Menu/Edit/Refactor/Convert to ObjC ARC) – Denis Kutlubaev Aug 21 '12 at 11:43
  • Please refer my this Link http://stackoverflow.com/a/9497342/1357774 – DivineDesert Aug 21 '12 at 12:41

3 Answers3

1

without knowing how many iterations you are going through in [keys count] you are doing a lot of NSString operations. Each "stringBy..." message is going to allocate a new autoreleased NSString instance which will not be released until you exit your loops. You may want to consider using NSMutableString instead and using

replaceOccurrencesOfString:withString:options:range:

To reduce the number of autoreleased objects you are creating (which will thereby reduce your application's memory footprint). See the NSMutableString documentation. Otherwise I suggest using the Allocations tool or something similar in Xcode to try and closer examine your memory footprint

Will Ayd
  • 6,767
  • 2
  • 36
  • 39
1

Its obvious that we are using a string that gets mutated every instances hence nsmutablestring is optimized solution .Also while analyzing the functions :

[NSMutableString replaceOccurrencesOfString:@"'" withString:@"''"]
[NSMutableString  appendString:]

in instruments they leave less memory foot-prints while comparing them with the previous you have used.

APD
  • 26
  • 3
0

For bulk insertion of records in database either using Sqlite or Core Data, always prefer to use loop in @autoreleasepool{}, because with this, all the objects in autorelease mode, will get nil after immediate use.

int m=0;

while ([arrData count]!=0) {

@autoreleasepool{

if (newQuery) {

    exeQuery = query;
    newQuery = false;

}
else 
{
    exeQuery=[exeQuery stringByAppendingFormat:@" UNION"];
}

NSMutableDictionary *data = [[NSMutableDictionary alloc] initWithDictionary:[arrData objectAtIndex:0]];

[data removeObjectForKey:@"statement"];
[data removeObjectForKey:@"datetime_stamp"];

NSString *strVal=@"";
NSString *_value=@"";

int i=0;
    for(;i<[keys  count]-1;i++)
    {
        if(_value==nil || _value==NULL){
            _value=@"";
        }

        _value=[NSString stringWithFormat:@"%@",[data objectForKey:[keys objectAtIndex:i]]];
        _value=[_value stringByReplacingOccurrencesOfString:@"'" withString:@"''"];

        strVal=[strVal stringByAppendingFormat:@"'%@',",_value];

    }

if(_value==nil || _value==NULL){
    _value=@"";
}

_value=[NSString stringWithFormat:@"%@",[data objectForKey:[keys objectAtIndex:i]]];
_value=[_value stringByReplacingOccurrencesOfString:@"'" withString:@"''"];

strVal=[strVal stringByAppendingFormat:@"'%@'",_value];


exeQuery=[exeQuery stringByAppendingFormat:@" SELECT %@",strVal];


if (m!=0 && m%499==0) {

    [DataSource executeQuery:exeQuery];

    //db.execute(exeQuery);
    newQuery = true;
}

[data release];

[arrData removeObjectAtIndex:0];

m++;
}

for (;m<locations_length; m++) {

if (newQuery) {

    exeQuery = query;
    newQuery = false;

}
else 
{
    exeQuery=[exeQuery stringByAppendingFormat:@" UNION"];
}

NSMutableDictionary *data = [[NSMutableDictionary alloc] initWithDictionary:[arrData objectAtIndex:m]];

[data removeObjectForKey:@"statement"];
[data removeObjectForKey:@"datetime_stamp"];

NSString *strVal=@"";
NSString *_value=@"";

int i=0;
    for(;i<[keys  count]-1;i++)
    {
        if(_value==nil || _value==NULL){
            _value=@"";
        }

        _value=[NSString stringWithFormat:@"%@",[data objectForKey:[keys objectAtIndex:i]]];
        _value=[_value stringByReplacingOccurrencesOfString:@"'" withString:@"''"];

        strVal=[strVal stringByAppendingFormat:@"'%@',",_value];

    }

if(_value==nil || _value==NULL){
    _value=@"";
}

_value=[NSString stringWithFormat:@"%@",[data objectForKey:[keys objectAtIndex:i]]];
_value=[_value stringByReplacingOccurrencesOfString:@"'" withString:@"''"];

strVal=[strVal stringByAppendingFormat:@"'%@'",_value];


exeQuery=[exeQuery stringByAppendingFormat:@" SELECT %@",strVal];


if (m!=0 && m%499==0) {

    [DataSource executeQuery:exeQuery];

    //db.execute(exeQuery);
    newQuery = true;
}

[data release]; 

}


}
Ankit Thakur
  • 4,739
  • 1
  • 19
  • 35
  • But if there is a lot of data you will use too much memory (as the pool isn't drained until the loop is complete). – trojanfoe Aug 21 '12 at 11:45
  • On the right path here, but you need to add more of them inside the for loops. The one big one might not do it. – David H Aug 21 '12 at 11:54
  • it is using @autoreleasepool{} anotation which is started from iOS-5. You can start it with NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; and just before [data release]; you will be required to use [pool drain]; – Ankit Thakur Aug 24 '12 at 09:14