memory problems

Dec 25, 2012 at 10:09am
I am using VS2008.
I have a Windows Service application which creates Crystal Reports. This is
a multi theaded application which can run several reports at one time.
My problem - there is a memory leak someplace. I can not detect the memory
leak by running several reports by hand, but when I run tha app as a
servrice and process few hundred reports there is significant memory leak.
The application can consume over 1GB of memory where it should not go over
200 mb. I have few other applications that use Crystal Reports and those
applications do not have memory leak, the big difference is those
applications are single threaded.

My question: are there any tools, books, tutorials that can help me to find the memory leak?
Dec 25, 2012 at 10:34am
There aren't any book, or tool which can help you find and solve your memory leak problem rapidly and directly. :)
But the cause : Yes. Here are several causes :
1- You allocated dynamic memory (pointers) but you forgot to delete (free) them.
2- Your structures have a lot of members, probably this means not all variables are used completely, so also it may cause memory leak.

Edit : Sorry, maybe my first answer is wrong :)
Last edited on Dec 25, 2012 at 10:45am
Dec 25, 2012 at 10:42am
Of course there are dedicated tools for that, like Visual Leak Detector and many others :

http://vld.codeplex.com/

However, you cannot easily debug a windows service as it is, just debug your EXE as any normal console applicaton (it could be required to first change your application code to be able to do that, it depends how it is written)
Last edited on Dec 25, 2012 at 10:45am
Dec 26, 2012 at 2:20pm
I can recommend to read a book "Effective C++" and you can read in wikipedia or softpedia about different debuggers (VLD, Purifu, MemCheck, DrMemory, Deleaker). Also, read about object oriented programming.
Dec 27, 2012 at 12:08pm
I get it. Perhaps you can share books or links to a good library?
Dec 28, 2012 at 2:34pm
Just search in google))
Dec 28, 2012 at 10:48pm
You may use some block code to detect memory leak. (Where you doubt)

Good luck.
Jan 8, 2013 at 9:34pm
What block? I've never heard about it. Maybe I do not quite understand you.
Jan 9, 2013 at 11:39am
Ok, Please, check the Task Manager.

"Block code" in my opinion is the code which is only used to debug (usually complex programs) that standard debug feature cannot.
Some functions which can do this effectively (which I'm currently using in many big projects) :


- Sleep();
- exit();
- ExitProcess();
- MessageBox();
- FatalAppExit();
- sprintf, printf


1
2
3
int *var;

*var = 10; //Crash! 


1
2
3
4
int *var;
MessageBox(0,"Hahahaha","Hihihi",0);
*var = 10; 
MessageBox(0,"HoHoHoHo","Hihihi",0); //"Hohohoho" is never reached -> The problem here - *var = 10; 


About your memory leak : You also can use this to watch your program progress (with your Task Manager) A very simple example :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
void SetValue(double *var, double value)
{
     var = new double(); //Suppose you forgot to free "var"
     *var = value;
}

int main()
{
double *a, b, c;

b = 10;
c = 15;
for(int i = 0;i < 10000000;i++)
{
     SetValue(a, i);
     b = pow(*a, 2);
     c = pow(b, 2);
}
return 0;
}

Certainly It causes memory leak.

Now, you put some block code, for example :

1
2
3
4
5
6
7
for(int i = 0;i < 10000000;i++)
{
     SetValue(a, i);b = pow(*a, 2);c = pow(b, 2);

     Sleep(1); //Sleep block command
}
MessageBox(0,"Done.","!!!",0); //MessageBox block command 


Now you open up the Task Manager and see the program memory-consuming grows up and up. Test it, and you will see.

Another example :
1
2
3
Sleep(5000);
function([...]); //which is very questionable
MessageBox(0,"Done.","!!!",0);

Open the Task Manager, the open your program, wait for 5 seconds. Look at your program process and find information "Memory Usage". Watch it closely. Then you'll see memory leak. :)

Then you basically detected the problem. Expand the code and continue putting the block code (where you doubt). Many fatal errors or (memory leak) errors can be avoided. :)
Last edited on Jan 9, 2013 at 12:01pm
Jan 9, 2013 at 12:29pm
closed account (o3hC5Di1)
Just on a sidenote, you may want to have a quick look at this link: http://vld.codeplex.com/

All the best,
NwN
Jan 9, 2013 at 12:34pm
NwN wrote:
...you may want to have a quick look at this link: http://vld.codeplex.com/

That's good stuff. I'll try it out. :)
Jan 9, 2013 at 2:31pm
Thanks, I already read this article. I learned how to manage memory. Can I prevent leaks? How to protect code from the leak? Or is it impossible?
Jan 9, 2013 at 3:36pm
closed account (zb0S216C)
It's possible to prevent memory leaks by simply being careful. The example code provided by Jackson Marie intentionally (I hope) shows lack of care and logic. In general, allocating different blocks of memory is a good way to leak memory unless you utilise the use of smart pointers. However, common solutions are memory pools or garbage collection.

A memory pool is a large pre-allocated block of memory that is capable of storing any type of information. This pool of memory is normally managed by an interface which the program uses to store its data. Memory pools themselves do not leak if the pool is released. However, if an object's constructor is called, the corresponding destructor must be called.

A garbage collection system is a system that automatically frees allocated memory which saves the programmer from developing time-consuming memory management systems. A leaking GBS almost never happens.

My opinion on GBSs:
They do save the programmer time, but they don't teach proper discipline of memory like C/C++ does. Personally, I avoid GB at all costs; it's bad for my mental well-being.


Wazzak
Last edited on Jan 9, 2013 at 3:47pm
Jan 9, 2013 at 5:15pm
> Can I prevent leaks? How to protect code from the leak? Or is it impossible?

It is very easy to prevent resource leaks - just use RAII consistently.

Not this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
my_class* bad_code( const char* cstr )
{
    my_class* pmc = new my_class( /* ... */ ) ;

    try
    {
        // call a function

        std::FILE* file = std::fopen( /* ... */ ) ;

        try
        {
            // ...
            // call a function

            char* cpy = static_cast<char*>( new char [ cstr ? 1 : std::strlen(cstr) + 1 ] ) ;
            if( cstr ) std::strcpy( cpy, cstr ) ;
            else cstr[0] = 0 ;

            try
            {
                // ...
                // call a function

                int* array = new int[100000] ;
                std::memset( array, 0, sizeof(array) ) ;

                try
                {
                    // ...
                    // call a function
                }
                catch( ... )
                {
                    delete[] array ;
                    throw ;
                }

                 delete[] array ;
             }
             catch(...)
             {
                 delete [] array ;
                 throw ;
             }
             delete [] cpy ;
        }
        catch( ... )
        {
            std::fclose(file) ;
            throw ;
        }
        std::fclose(file) ;
    }
    catch( ... )
    {
        delete pmc ;
        throw ;
    }

    return pmc ; // dump this problem on the unfortunate caller
}


But this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
std::shared_ptr<my_class> good_code( const std::string& str )
{
    std::shared_ptr<my_class> pa = std::make_shared<my_class>( /* ... */ ) ;

    // ...
    // call a function; no worries if it throws

    std::fstream file( /* ... */ ) ;

    // ...
    // call a function; no worries if it throws

    std::string cpy = str ;

    // ...
    // call a function; no worries if it throws

    std::vector<int> array(100000) ;

    // ...
    // call a function; no worries if it throws

    return pa ;
}
Jan 9, 2013 at 7:15pm
closed account (o3hC5Di1)
Just out of interest: When you say RAII, at present it's mostly done so by using smart pointers and STL containers as you showed right? I mean as opposed to opening a resource (or initialising a pointer) in the constructor (and providing fail safety there) and cleaning it up in the destructor?

All the best,
NwN
Jan 10, 2013 at 2:59am
> Just out of interest: When you say RAII, at present it's mostly done so
> by using smart pointers and STL containers as you showed right?

Yes. The standard library also provides RAII mechanisms for other resources that it encapsulates; for example std::lock_guard and friends.


> as opposed to opening a resource (or initialising a pointer) in the constructor (and providing fail safety there)
> and cleaning it up in the destructor?

In many programs, we have to deal with resources that are not provided by the standard library. For example, there may be a database library written in C that we want to use. And it has the usual suite of sandwich functions:

1
2
3
// locks database table, returns -1 on failure
int lock_db_table( const char* table_name ) ;
void unlock_db_table( int lock_id ) ;

Now, if we use this as it is in several places, our C++ code would metamorphose into Java-like spaghetti. To avoid that, we wrap the management of the raw resource in a shim class:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
struct scoped_db_table_lock
{
    explicit scoped_db_table_lock( const char* table_name ) : lock_id( lock_db_table(table_name) ) {}
    ~scoped_db_table_lock() { if( lock_id != INVALID ) unlock_db_table(lock_id) ; }

    operator bool() const { return lock_id != INVALID ; }
    bool operator! () const { return lock_id == INVALID ; }

    scoped_db_table_lock( const scoped_db_table_lock& ) = delete ;
    scoped_db_table_lock& operator= ( const scoped_db_table_lock& ) = delete ;

    scoped_db_table_lock( scoped_db_table_lock&& that ) : lock_id(that.lock_id) { that.lock_id = INVALID ; }
    scoped_db_table_lock& operator= ( scoped_db_table_lock&& that )
    {
        if( std::addressof(that) != this )
        {
            if( lock_id != INVALID ) unlock_db_table(lock_id) ;
            lock_id = that.lock_id ;
            that.lock_id = INVALID ;
        }
        return *this ;
    }

    private:
        int lock_id ;
        enum { INVALID = -1 } ;
};


Such a wrapper classes would have code that deals directly with raw resources; and they should be the only ones doing so.
Jan 10, 2013 at 11:04am
closed account (o3hC5Di1)
All right, thanks very much for clearing that up :)

All the best,
NwN
Jan 10, 2013 at 8:42pm
Thank you Framework!!! At last I got the answer to my question!
Jan 11, 2013 at 5:08pm
"Yes. The standard library also provides RAII mechanisms for other resources that it encapsulates; for example std::lock_guard and friends. "
I was interested in it! Thanks for the clarification!
Jan 14, 2013 at 11:10am
Thank you all! Problem solved.
Thread is closed
Topic archived. No new replies allowed.