🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Thread View: comp.database.ms-access
4 messages
4 total messages Started by Paul Maia Fri, 12 Jul 2002 00:10
ADO Memory Leak - Please Help
#3
Author: Paul Maia
Date: Fri, 12 Jul 2002 00:10
118 lines
5983 bytes
I appeal to the community for help... for I have failed...

I have beaten my head against a wall trying to find the problem and
have come up blank. I have an application that writes an Access
database record about every 3-4 seconds. After running for several
days I looked at Task Manager and noticed that it was consuming
memory with every 3-4 records written (task manager only seems to
have a 1-2k granularity). I have updated MDAC to 2.62 SP2 and
Jet 4.0 Database to SP6 and the memory creep continues.

I am fairly sure that it is something I am doing, but I am not familiar
enough with the ADO API's to know the hidden secrets, yet. Any
help would be greatly appreciated.

The following code has the exception handling removed to simplify
the post.With logging in each of the exception handlers, I have
determined that there are no exceptions occurring.

The code below is in a VC++ 6.0 (latest SP) DLL, that is called from
C++ Builder.

The DATABASE_HANDLE looks like...

-----------------------------------------------------------
typedef struct DATABASE_HANDLE
{
    ADODB::_ConnectionPtr conRef;
    char databaseDSN[MAX_STRING];
    char userID[MAX_STRING];
    char password[MAX_STRING];
    long ADO_ErrorIdx;
    char *curErrMessage;
} DATABASE_HANDLE;
-----------------------------------------------------------

I open the Database and leave it open (for weeks), writing the data to the
database. Even if there was a leak in it, it would not (I hope) contribute
to
the leak that occurs on each addition to the database. Even though, if I
close
and re-open it, the previous creep level is the new starting point.

But, for completeness, here is a snippet of the code to open the database:

-----------------------------------------------------------
        // initialize the connection object
        dbHandle->conRef = NULL;
        (void)dbHandle->conRef.CreateInstance(__uuidof(ADODB::Connection));
        // make sure it is opened read/write
        dbHandle->conRef->Mode = ADODB::adModeReadWrite;
        // (default)
        //  only allow viewing of transactions, once they are committed
        dbHandle->conRef->IsolationLevel = ADODB::adXactCursorStability;
        // set the attributes, no attributes
        dbHandle->conRef->Attributes = 0;
        // save the DSN
        strncpy(dbHandle->databaseDSN, databaseDSN, MAX_STRING);
        // open the database
        (void)dbHandle->conRef->Open(databaseDSN, userID, password,
            ADODB::adConnectUnspecified);

-----------------------------------------------------------

-----------------------------------------------------------
ADOWRITE_API BOOL ADO_AddNewRecordToDatabase(DATABASE_HANDLE *dbHandle,
    const char * const tableName, const char * const fields[],
    const char * const values[], int itemCount)
{
    ADODB::_RecordsetPtr recRef = NULL;
    BOOL retCode = FALSE;

    // now add a record to the database
    if (dbHandle->conRef->State == (int)ADODB::adStateOpen)
    {
        int x;
        (void)recRef.CreateInstance(__uuidof(ADODB::Recordset));
        // since we are only adding records here,
        //  a forward -only cursor would be the fastest
        recRef->CursorType = ADODB::adOpenForwardOnly;
        // open the recordSet
        (void)recRef->Open(tableName,
            _variant_t((IDispatch *)dbHandle->conRef, true),
            ADODB::adOpenKeyset, ADODB::adLockOptimistic,
            (int)ADODB::adCmdTable);
        // create a new data record
        (void)recRef->AddNew();
        // add the fields/values
        for (x = 0; x < itemCount; x++)
        {
            (void)recRef->Fields->GetItem(_variant_t(fields[x]))->
                 put_Value(_variant_t(values[x]));
        }
        // update it to the database
        (void)recRef->Update();
        // it's there
        retCode = TRUE;
        // close the recordset
        (void)recRef->Close();
        // free the recordset
        recRef = NULL;
    }
    else
    {   // add as a local message
        AddLogEntry("[ADO_AddNewRecordToDatabase] "
            "ConRef->State Does Not Show The Database Open");
    }
    // clear all errors
    (void)dbHandle->conRef->Errors->Clear();
    // return to caller
    return(retCode);
}
-----------------------------------------------------------

Your consideration is greatly appreciated,

Paul Maia
paul_maia@hotmail.no^^spam.com
remove no^^spam to reply
Re: ADO Memory Leak - Please Help
#4
Author: Val Mazur
Date: Fri, 12 Jul 2002 13:17
138 lines
6264 bytes
Hi,

Check if this is not your case.

http://support.microsoft.com/default.aspx?scid=kb;en-us;Q247140

I think you would need to close your connection periodically to free you
allocated memory

--
Val Mazur
Microsoft MVP

"Paul Maia" <pmaia@austin.rr.com> wrote in message
news:n8pX8.99782$q53.2352660@twister.austin.rr.com...
> I appeal to the community for help... for I have failed...
>
> I have beaten my head against a wall trying to find the problem and
> have come up blank. I have an application that writes an Access
> database record about every 3-4 seconds. After running for several
> days I looked at Task Manager and noticed that it was consuming
> memory with every 3-4 records written (task manager only seems to
> have a 1-2k granularity). I have updated MDAC to 2.62 SP2 and
> Jet 4.0 Database to SP6 and the memory creep continues.
>
> I am fairly sure that it is something I am doing, but I am not familiar
> enough with the ADO API's to know the hidden secrets, yet. Any
> help would be greatly appreciated.
>
> The following code has the exception handling removed to simplify
> the post.With logging in each of the exception handlers, I have
> determined that there are no exceptions occurring.
>
> The code below is in a VC++ 6.0 (latest SP) DLL, that is called from
> C++ Builder.
>
> The DATABASE_HANDLE looks like...
>
> -----------------------------------------------------------
> typedef struct DATABASE_HANDLE
> {
>     ADODB::_ConnectionPtr conRef;
>     char databaseDSN[MAX_STRING];
>     char userID[MAX_STRING];
>     char password[MAX_STRING];
>     long ADO_ErrorIdx;
>     char *curErrMessage;
> } DATABASE_HANDLE;
> -----------------------------------------------------------
>
> I open the Database and leave it open (for weeks), writing the data to the
> database. Even if there was a leak in it, it would not (I hope) contribute
> to
> the leak that occurs on each addition to the database. Even though, if I
> close
> and re-open it, the previous creep level is the new starting point.
>
> But, for completeness, here is a snippet of the code to open the database:
>
> -----------------------------------------------------------
>         // initialize the connection object
>         dbHandle->conRef = NULL;
>
(void)dbHandle->conRef.CreateInstance(__uuidof(ADODB::Connection));
>         // make sure it is opened read/write
>         dbHandle->conRef->Mode = ADODB::adModeReadWrite;
>         // (default)
>         //  only allow viewing of transactions, once they are committed
>         dbHandle->conRef->IsolationLevel = ADODB::adXactCursorStability;
>         // set the attributes, no attributes
>         dbHandle->conRef->Attributes = 0;
>         // save the DSN
>         strncpy(dbHandle->databaseDSN, databaseDSN, MAX_STRING);
>         // open the database
>         (void)dbHandle->conRef->Open(databaseDSN, userID, password,
>             ADODB::adConnectUnspecified);
>
> -----------------------------------------------------------
>
> -----------------------------------------------------------
> ADOWRITE_API BOOL ADO_AddNewRecordToDatabase(DATABASE_HANDLE *dbHandle,
>     const char * const tableName, const char * const fields[],
>     const char * const values[], int itemCount)
> {
>     ADODB::_RecordsetPtr recRef = NULL;
>     BOOL retCode = FALSE;
>
>     // now add a record to the database
>     if (dbHandle->conRef->State == (int)ADODB::adStateOpen)
>     {
>         int x;
>         (void)recRef.CreateInstance(__uuidof(ADODB::Recordset));
>         // since we are only adding records here,
>         //  a forward -only cursor would be the fastest
>         recRef->CursorType = ADODB::adOpenForwardOnly;
>         // open the recordSet
>         (void)recRef->Open(tableName,
>             _variant_t((IDispatch *)dbHandle->conRef, true),
>             ADODB::adOpenKeyset, ADODB::adLockOptimistic,
>             (int)ADODB::adCmdTable);
>         // create a new data record
>         (void)recRef->AddNew();
>         // add the fields/values
>         for (x = 0; x < itemCount; x++)
>         {
>             (void)recRef->Fields->GetItem(_variant_t(fields[x]))->
>                  put_Value(_variant_t(values[x]));
>         }
>         // update it to the database
>         (void)recRef->Update();
>         // it's there
>         retCode = TRUE;
>         // close the recordset
>         (void)recRef->Close();
>         // free the recordset
>         recRef = NULL;
>     }
>     else
>     {   // add as a local message
>         AddLogEntry("[ADO_AddNewRecordToDatabase] "
>             "ConRef->State Does Not Show The Database Open");
>     }
>     // clear all errors
>     (void)dbHandle->conRef->Errors->Clear();
>     // return to caller
>     return(retCode);
> }
> -----------------------------------------------------------
>
> Your consideration is greatly appreciated,
>
> Paul Maia
> paul_maia@hotmail.no^^spam.com
> remove no^^spam to reply
>
>
>
>
Re: ADO Memory Leak - Please Help
#5
Author: Roy Fine
Date: Fri, 12 Jul 2002 22:05
163 lines
7607 bytes
Paul

what you are most likely seeing is not a classic "memory leak", else you
would never regain the memory when closing the connection -- if it were
truly "leaked", it would only be freed when the OS cleaned up during process
termination.  ADO is implemented on OLEDB, and OLEDB providers (should) use
IMalloc for all dynamic memory allocation.  You can can implement
IMallocSpy, and in the PreAlloc and PostFree methods you can maintain a list
of allocated blocks.  You can also implement PreHeapMinimize to see how
often and under what conditions the memory manager cleans up and takes out
the garbage.

I think you will see that the OLEDB rowset data is held and not released
until either :
1) the session is closed, or
2) a call ot Alloc fails.

For your case - especially if you are concerned with performance, discard
the Recordset and implement the rowset additions using a parameterized,
persistent and prepared SQL Insert with the ADO::Command and ADO::Parameter
objects..  Opening any sort of Recordset just to do an insert or update is
typically the wrong way to go about the add/update.

Contrary to what others in this thread has suggested, do not take the route
of open/close the connection every time you need to do the add or update.
Creating a session object is very resource intensive, do it once and save
it -- they are meant to be persistent over a period of time.  (Connection
object like to celebrate birthdays too!)

best regards,
roy fine







"Paul Maia" <pmaia@austin.rr.com> wrote in message
news:n8pX8.99782$q53.2352660@twister.austin.rr.com...
> I appeal to the community for help... for I have failed...
>
> I have beaten my head against a wall trying to find the problem and
> have come up blank. I have an application that writes an Access
> database record about every 3-4 seconds. After running for several
> days I looked at Task Manager and noticed that it was consuming
> memory with every 3-4 records written (task manager only seems to
> have a 1-2k granularity). I have updated MDAC to 2.62 SP2 and
> Jet 4.0 Database to SP6 and the memory creep continues.
>
> I am fairly sure that it is something I am doing, but I am not familiar
> enough with the ADO API's to know the hidden secrets, yet. Any
> help would be greatly appreciated.
>
> The following code has the exception handling removed to simplify
> the post.With logging in each of the exception handlers, I have
> determined that there are no exceptions occurring.
>
> The code below is in a VC++ 6.0 (latest SP) DLL, that is called from
> C++ Builder.
>
> The DATABASE_HANDLE looks like...
>
> -----------------------------------------------------------
> typedef struct DATABASE_HANDLE
> {
>     ADODB::_ConnectionPtr conRef;
>     char databaseDSN[MAX_STRING];
>     char userID[MAX_STRING];
>     char password[MAX_STRING];
>     long ADO_ErrorIdx;
>     char *curErrMessage;
> } DATABASE_HANDLE;
> -----------------------------------------------------------
>
> I open the Database and leave it open (for weeks), writing the data to the
> database. Even if there was a leak in it, it would not (I hope) contribute
> to
> the leak that occurs on each addition to the database. Even though, if I
> close
> and re-open it, the previous creep level is the new starting point.
>
> But, for completeness, here is a snippet of the code to open the database:
>
> -----------------------------------------------------------
>         // initialize the connection object
>         dbHandle->conRef = NULL;
>
(void)dbHandle->conRef.CreateInstance(__uuidof(ADODB::Connection));
>         // make sure it is opened read/write
>         dbHandle->conRef->Mode = ADODB::adModeReadWrite;
>         // (default)
>         //  only allow viewing of transactions, once they are committed
>         dbHandle->conRef->IsolationLevel = ADODB::adXactCursorStability;
>         // set the attributes, no attributes
>         dbHandle->conRef->Attributes = 0;
>         // save the DSN
>         strncpy(dbHandle->databaseDSN, databaseDSN, MAX_STRING);
>         // open the database
>         (void)dbHandle->conRef->Open(databaseDSN, userID, password,
>             ADODB::adConnectUnspecified);
>
> -----------------------------------------------------------
>
> -----------------------------------------------------------
> ADOWRITE_API BOOL ADO_AddNewRecordToDatabase(DATABASE_HANDLE *dbHandle,
>     const char * const tableName, const char * const fields[],
>     const char * const values[], int itemCount)
> {
>     ADODB::_RecordsetPtr recRef = NULL;
>     BOOL retCode = FALSE;
>
>     // now add a record to the database
>     if (dbHandle->conRef->State == (int)ADODB::adStateOpen)
>     {
>         int x;
>         (void)recRef.CreateInstance(__uuidof(ADODB::Recordset));
>         // since we are only adding records here,
>         //  a forward -only cursor would be the fastest
>         recRef->CursorType = ADODB::adOpenForwardOnly;
>         // open the recordSet
>         (void)recRef->Open(tableName,
>             _variant_t((IDispatch *)dbHandle->conRef, true),
>             ADODB::adOpenKeyset, ADODB::adLockOptimistic,
>             (int)ADODB::adCmdTable);
>         // create a new data record
>         (void)recRef->AddNew();
>         // add the fields/values
>         for (x = 0; x < itemCount; x++)
>         {
>             (void)recRef->Fields->GetItem(_variant_t(fields[x]))->
>                  put_Value(_variant_t(values[x]));
>         }
>         // update it to the database
>         (void)recRef->Update();
>         // it's there
>         retCode = TRUE;
>         // close the recordset
>         (void)recRef->Close();
>         // free the recordset
>         recRef = NULL;
>     }
>     else
>     {   // add as a local message
>         AddLogEntry("[ADO_AddNewRecordToDatabase] "
>             "ConRef->State Does Not Show The Database Open");
>     }
>     // clear all errors
>     (void)dbHandle->conRef->Errors->Clear();
>     // return to caller
>     return(retCode);
> }
> -----------------------------------------------------------
>
> Your consideration is greatly appreciated,
>
> Paul Maia
> paul_maia@hotmail.no^^spam.com
> remove no^^spam to reply
>
>
>
>
Re: ADO Memory Leak - Please Help
#6
Author: Paul Maia
Date: Fri, 12 Jul 2002 22:52
43 lines
2841 bytes
Thanks for your reply, Val. I had previously read that article and
installed Jet 4.0 SP6 on both of my test boxes. The article is kind-of
vague about what the symptoms would be after the upgrade. But, in my
case, the program is still consuming memory at about 80% the rate that
the datbase grows. In the last 24 hours the database grew 1.51
megabytes and Peak Memory Usage has grown by 1.36 megabytes.

As for coding the work around anyway, I did not consider it since I
did what it indicated to do in the first case.

One thing I did do, was to write a test program (using the exact code
that I am using in the main app) that opens the database, writes 1000
records and closes the database. Using CodeGuard, I have confirmed
that my test app is not leaking memory. As a test, I stubbed out the
database call (so that all of the other code runs) in the test app and
am confident the leak is the database DLL or ADO. The test app leaks
memory just as it does in the main app.

Other notes:
* I have confirmed if I don't start the Database Thread, that the
program does not appear to 'leak' memory.
* Windows 2000, SP2. Jet/MDAC 4.0 SP6.
* DLL is in VC++ 6.0 with latest SP. Application is in C++ Builder 5,
latest Patches.

Thanks,

Paul Maia

"Val Mazur" <group51a@hotmail.com> wrote in message news:<uv12UZaKCHA.2552@tkmsftngp08>...
> Hi,
> 
> Check if this is not your case.
> 
> http://support.microsoft.com/default.aspx?scid=kb;en-us;Q247140
> 
> I think you would need to close your connection periodically to free you
> allocated memory
> 
> --
> Val Mazur
> Microsoft MVP
~snip~
Thread Navigation

This is a paginated view of messages in the thread with full content displayed inline.

Messages are displayed in chronological order, with the original post highlighted in green.

Use pagination controls to navigate through all messages in large threads.

Back to All Threads