Memory not decreasing after a series of insertions in the database - ios

I have simple code that inserts values into my database:
-(void)inserirBd:(NSString *)valores{
sqlite3_stmt *statement;
// Get the documents directory
NSArray *dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docsDir = dirPaths[0];
// Build the path to the database file
databasePath = [[NSString alloc] initWithString: [docsDir stringByAppendingPathComponent:#"fazerbem.sqlite"]];
const char *dbpath = [databasePath UTF8String];
if (sqlite3_open(dbpath, &myDatabase) == SQLITE_OK) {
NSString *insertSQL = valores;
const char *insert_stmt = [insertSQL UTF8String];
sqlite3_prepare_v2(myDatabase, insert_stmt,
-1, &statement, NULL);
if (sqlite3_step(statement) == SQLITE_DONE) {
} else {
NSLog(#"Error -> %s", sqlite3_errmsg(myDatabase));
}
sqlite3_finalize(statement);
sqlite3_close(myDatabase);
}
}
and I am calling this function in this way:
cInsert = [NSString stringWithFormat:#"INSERT INTO fazerbem_products (value) Values ('%#')", p1_1.text,];
InsertBD *insert = [[InsertBD alloc] init];
[insert inserirBd:cInsert];
To perform some tests of memory, I put the above command in a loop that will insert a repeat this 85,000 times, in debug memory, before inserting the values ​​into the database the memory was 1.1 MB, after performing the loop the memory rose to around 500 MB.
But after that, why not the memory lowered to 1.1 MB again? since the loop was already processed and in this case the memory should be released ? (I'm using ARC, and my app only have a button to do this)

The Xcode Debug Memory report is not what either you want nor what you think it is.
The Debug Navigator shows the same things as the "Activity Monitor" instrument. It is not showing current live memory by your app, it's showing current memory allocated to your app by the OS. The OS will reclaim unused but allocated memory as needs arise.
The concept is to avoid allocation memory blocks from the system, deallocating only to need to re-allocate later. There is a difference between the system allocation memory (large blocks) to an app and the app allocation memory to an object (portions of the large blocks). You care about the second, the system cares about the first.
See this SO Answer Here by #Putz1103 for complete details.
Use Instruments and look at Live Bytes to see the actual memory usage.

Related

iphone - improve INSERT into sqlite

In my app, I need to INSERT multiple times some entry.
Each time, I am using this function:
- (int) insertFunction:(NSString *)stringa{
NSDate * start = [NSDate date];
sqlite3_stmt *statement;
NSString *file = [self getWritableDBPath];
if (sqlite3_open([file UTF8String] , &_database) == SQLITE_OK)
{
NSString *insertSQL = [NSString stringWithFormat:#"%#",stringa];
const char *insert_stmt = [insertSQL UTF8String];
sqlite3_prepare_v2(_database, insert_stmt, -1, &statement, NULL);
if (sqlite3_step(statement) == SQLITE_DONE)
{
//NSLog(#"Contact added");
} else {
NSLog(#"Failed to add contact");
}
sqlite3_finalize(statement);
}
sqlite3_close(_database);
int row_id = (int)sqlite3_last_insert_rowid(_database);
NSLog(#"SINGLE INSERT took: %f", -[start timeIntervalSinceNow]);
return row_id;
}
that took about 0.020 second, and make my app frezing about 5 second.
-EDIT- My getWritableDBPath is:
- (NSString *) getWritableDBPath {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory , NSUserDomainMask, YES);
NSString *documentsDir = [paths objectAtIndex:0];
return [documentsDir stringByAppendingPathComponent:DATABASE_NAME];
}
What I can do to improve that time? For example, avoiding to open the data base each time? In this case how?
Thanks in advance
You might want to look at the closeDatabase call, if the version of SQLite you are using is new enough it will probably have placed your writes into the WAL and will be committing them into the main database. Although 5 seconds does seems quite slow.
For your other comment about leaving the database open, simply call the open one time only and hold onto the sqlite3* handle in a class variable, and then close it when the class gets dealloc'ed, you will see much better performance.

how to scroll a uiwebview using uiscrollview

i have a UIWebView over a UIScrollView. i use some js files to draw some graph like line that will update when the time value changes.
The Problem
Im not able to scroll when the points goes out of the screen.
I'm new to IOS Development so please help me.
thank in advance
After Completion the QUERY, You need to close transaction.
Here's the sample code for you...
// Get the documents directory
dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
docsDir = [dirPaths objectAtIndex:0];
// Build the path to the database file
databasePath = [[NSString alloc] initWithString: [docsDir stringByAppendingPathComponent: #"YOURDB.db"]];
const char *dbpath = [databasePath UTF8String];
if (sqlite3_open(dbpath, &DB) == SQLITE_OK)
{
NSString *query=[NSString stringWithFormat:#"insert into studentDetails (NAME,Email,adressL1,adressL2,phone,landline,department,DoB,fatherName) values (\"%#\",\"%#\",\"%#\",\"%#\",\"%#\",\"%#\",\"%#\",\"%#\",\"%#\")",
name.text,
email.text,
addressLine1.text,
addressLine2.text,
phone.text,
Landline.text,
Department.text,
DoB.text,
fname.text];
const char *insert_stmt = [insertSQL UTF8String];
sqlite3_prepare_v2(YOURDB, insert_stmt, -1, &statement, NULL);
if (sqlite3_step(statement) == SQLITE_DONE)
{
NSLog(#" Successfully added");
} else {
NSLog(#" Failed added");
NSLog(#"Error %s",sqlite3_errmsg(ExplorejaipurDB));
}
}
sqlite3_finalize(statement);
sqlite3_close(YOURDB);
}
The database could be locked because of several reasons:
Multiple queries running
multiple threads running
opened the database multiple times
Check your code and see if you have closed the connections to the database sqlite3_close(). A good idea would also be to use sqlite3_finalize() after each SQL statement when you are done with it.
So try try to match all your sqlite3_open() with sqlite3_close() and sqlite3_prepare() (if you are using it) with sqlite3_finalize()

Is SQLite able to update or insert

I am facing a problem in Xcode : I tried many weeks to add data into sqlite database and I surf Google for many results but none of them can give a complete and clear tutorial, most of them are using .db but not sqlite, I suspect that sqlite is not able to insert or update, just can read data, or is there any other way to do it?
Please attach the link with tutorial in the answer if you guys have any. Thank you
I suspect that sqlite is not able to insert or update, just can read
data
Of course you can insert data in SQLite. This is a database just as other ones, just a little lighter and embedded in the same process as your application instead of a different one as is usually the case (this both means SQLite can't answer to more than one client, and that you don't have to install anything on the computer apart your application).
Here's the INSERT documentation : http://www.sqlite.org/lang_insert.html
And here's a tutorial among many other ones : http://www.techotopia.com/index.php/An_Example_SQLite_based_iPhone_Application
(in fact I just googled for "sqlite xcode insert", I didn't knew this tutorial before)
Sunny it's been two days that im working to find out how to insert data to sqlite on iOS. First thing you should do is to tell SQLite to where save the data. By default if you run ur app on ur phone it will put the sqlite file in a readonly root. to solve it you should do this :
-(NSString *)GetDocumentDirectory{
fileMgr = [NSFileManager defaultManager];
homeDir = [NSHomeDirectory() stringByAppendingPathComponent:#"Documents"];
return homeDir;
}
which fileMgr is NSFileManager and homeDir is NSString next when you wanna insert yout data, first u should give ur SQLite root to it, which is the first line, and it checks if sqlite3_open and will start to insert your data:
-(void)InsertRecords:(NSMutableString *)myData{
NSString *dbPath = [self.GetDocumentDirectory stringByAppendingPathComponent:#"YOUR SQLITE FILE NAME.sqlite"];
const char *dbpath = [dbPath UTF8String];
sqlite3 *contactDB;
sqlite3_stmt *statement;
if (sqlite3_open(dbpath, &contactDB) == SQLITE_OK)
{
NSString *insertSQL = [NSString stringWithFormat: #"INSERT INTO tableName (tableColumn) VALUES (\"%#\")", myData];
const char *insert_stmt = [insertSQL UTF8String];
sqlite3_prepare_v2(contactDB, insert_stmt, -1, &statement, NULL);
if (sqlite3_step(statement) == SQLITE_DONE)
{
sqlite3_bind_text(statement, 1, [myData UTF8String], -1, SQLITE_TRANSIENT);
}
else {
NSLog(#"error");
}
sqlite3_finalize(statement);
sqlite3_close(contactDB);
}
}
hope it helps :)

Sqlite FTS doesn't work when compiling with LLVM on iOS

I've been developing an enterprise iPad app for a while now. Since the app development started almost 2 years ago, I needed to compile my own version SQLite from source, since the default SQLite library (the sqlite3.dylib) didn't have FTS enabled by default.
Ok, everything was working fine since then. I've been always using GCC as the project compiler.
The thing is that now I'm trying to convert my whole project to use ARC. To do so, I need to use Apple's LLVM compiler.
That's it. When I change the compiler (from GCC 4.2 to LLVM 3.1 or 4.0, without converting to ARC, and without changing anything else), my app builds fine, everything runs ok, except by my FTS queries, which don't work at all Even the simplest ones. They run and return always with no result (with a SQLITE_OK code, though).
I'm stuck here. I have already talked to an Apple engineer at WWDC'12 but we couldn't find any solution.
I guarantee that it is unlikely to be a malformed query or something like that since the app is working fine with GCC. Also, I'm able to run the queries on the Terminal version of SQLite (or using other apps, like Base)
I was also using an old version of SQLite, but I've updated to the most recent version to date (3.7.13). Everything stays the same. I've also noticed that, now (I don't know since when) the sqlite that comes with the mac supports FTS (!!!) and I was able to remove my own version and use Apple's one. The thing is, I'm having the exact same behavior.
I've been looking for a solution, but couldn't find one. I've found some bugs related to armv6 and compiler optimisations (which can be fixed by using the -mno-thumb flag), but it's not my case. I also noticed that when I analyse my custom sqlite files using Clang it points out many, many "potencial errors".
I have this non-skeptical view and I (still) don't believe that it's a LLVM or SQLite bug. I prefer to check everything that is possible before addressing them a bug. Maybe I'm forgetting to configure something or need to add some flag to the compiler that I'm not doing.
I appreciate any help. Again, the bug only occurs on projects compiled with LLVM (even with the default sqlite). If I run the same queries on the Terminal version of sqlite3, everything goes fine.
UPDATE:
This code works. It creates a new database, a new virtual table using fts, insert a couple of items and then execute the select. I'll try more complex queries later, but, for now, it seems that the issue with my app might be, as expected, a bug in my code.
NSArray *dirPaths = dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docsDir = [dirPaths objectAtIndex:0];
sqlite3 *database;
// Build the path to the database file
NSString *databasePath = [[NSString alloc] initWithString: [docsDir stringByAppendingPathComponent: #"test.db"]];
NSFileManager *filemgr = [NSFileManager defaultManager];
NSError *error = nil;
[filemgr removeItemAtPath:databasePath error:&error];
const char *dbpath = [databasePath UTF8String];
if (sqlite3_open(dbpath, &database) == SQLITE_OK)
{
char *errMsg;
const char *sql_stmt = "CREATE VIRTUAL TABLE IF NOT EXISTS pages USING fts3(title, body);";
if (sqlite3_exec(database, sql_stmt, NULL, NULL, &errMsg) != SQLITE_OK)
{
NSLog(#"Failed to create table");
} else {
sql_stmt = "INSERT INTO pages(docid, title, body) VALUES(53, 'Home Page', 'SQLite is a software...');";
if (sqlite3_exec(database, sql_stmt, NULL, NULL, &errMsg) != SQLITE_OK)
{
NSLog(#"Failed to insert");
}
sql_stmt = "INSERT INTO pages(title, body) VALUES('Download', 'All SQLite source code...');";
if (sqlite3_exec(database, sql_stmt, NULL, NULL, &errMsg) != SQLITE_OK)
{
NSLog(#"Failed to insert");
}
}
sqlite3_stmt *statement;
const char *query_stmt = "select * from pages where body match 'soft*';";
if (sqlite3_prepare_v2(database, query_stmt, -1, &statement, NULL) == SQLITE_OK)
{
if (sqlite3_step(statement) == SQLITE_ROW)
{
NSLog(#"%# - %#", [[NSString alloc] initWithUTF8String:(const char *) sqlite3_column_text(statement, 0)],
[[NSString alloc] initWithUTF8String:(const char *) sqlite3_column_text(statement, 1)]);
} else {
NSLog(#"no results");
}
sqlite3_finalize(statement);
}
sqlite3_close(database);
} else {
NSLog(#"Failed to open/create database");
}
After all, I've found the bug. It was in my code. In summary, that what I've found out:
If I have something like that (I know it's weird/wrong):
int a = 0;
a = a++;
NSLog(#"%d", a);
the logged value will be 1 if this code is compiled with gcc and 0 if compiled with llvm.
I don't know why, but that's another question :)

Memory leak problem?

How i releasing the dataArray from following snippet,
+(NSMutableArray *)getData: (NSString *)dbPath
{
NSMutableArray *_dataArray = [[NSMutableArray alloc] init];
if(sqlite3_open([dbPath UTF8String], &database) == SQLITE_OK)
{
NSString *sqlQuery = [NSString stringWithFormat:#"SELECT DISTINCT name FROM databaseTable"];
sqlite3_stmt *selectstmt;
if(sqlite3_prepare_v2(database, [sqlQuery UTF8String], -1, &selectstmt, NULL) == SQLITE_OK)
{
while (sqlite3_step(selectstmt) == SQLITE_ROW)
{
[_dataArray addObject:[NSString stringWithFormat:#"%d", sqlite3_column_int(selectstmt, 0)]];
}
}
sqlite3_finalize(selectstmt);
}
sqlite3_close(database);
return _dataArray;
}
The above method gives me memory leak and it getting me serious problem in future working of application.
return [_dataArray autorelease];
If you want to returned retained objects you need to make that clear by following the naming conventions. the method should start with new, create or copy. Otherwise you should return a autoreleased object.
I don't see any obvious leaks in the code you posted. The function is returning a NSMutableArray that has been allocated, so the caller would be responsible for calling release at some later point. Or, you may choose to make this an autorelease object.
Also, you probably want to call sqlite3_close() only if sqlite3_open() succeeded (i.e., move sqlite3_close() to inside the first if statement). Same idea for sqlite3_finalize().
There is some one-time initialization that SQLite does implicitly, but you shouldn't need to worry about that. Check the docs for:
int sqlite3_initialize(void);
int sqlite3_shutdown(void);
What type of object(s) are being reported as leaks?

Resources