3

We manage some muliplatform code, and I've ran into this strangest memory-leak that happens only on linux.

I have a class which does not inherit nor being inherited. Since it does not have any dynamic allocartions that need to deallocated, I did not define a destructor for it (It does have some self destructing members - none of which is a pointer).

We noticed that the generation (new) and destruction (delete) of this class is causing a memory leak. defining and implementing an empty destructor on the header file did not solve the leak. moving the implementation to a source file - Did solve it. This (the leak) does not happen on windows, but does on linux.

I suppose it has something to do with compiler optimizations - but if so, I realy want to know the basis of this phoenomena, so I will know how to avoid such leak again.

Does anybody have an idea why this is happening ?

Here is a sketch of the code (not the real one of course...)

//file config.h
class Config
{       
    public:
        Config(std::shared_ptr<PR_Config> prConfig)
        {mPRConfig = engineConfig; mConfigOccurences++;};
        ~Config(){}
        shared_ptr<PR_Config>...
        ...
        ...
        ...
        //some public functions

    private:
        shared_ptr<PR_Config>...
        ...
        ...
        ...
        //some private members of shared_ptr type
};


//file: ConfigChecker.cpp
bool ConfigChecker::CheckConfig()
{
    shared_ptr<Config>  localConfig;
    localConfig = GenerateConfig();
    //Do some stuff with local config. did not change the reference count...
    if (locakConfig)
        return true;
    return false;
}

//file: Utils.cpp
shared_ptr<Config>  GenerateConfig()
{
    shared_ptr<Config>  pConfig = new Config(/*som parameters here...*/)

    return pConfig;
}

important notes:

  • when moving the implemntation of ~Config to config.cpp file the leak stops.
  • we don't realy use shared_ptr but some other smart pointer with reference count and self-destruction. But I don't believe that it's doing the...
  • 1
    Please provide code that reproduces the problem. – Johan Råde Nov 09 '14 at 16:37
  • 2
    There's not really enough information to go on, but this can happen when deleting an object through a pointer to incomplete class (where the class is only known through a `struct X;` forward declaration). In this case the compiler is allowed to assume that the destructor is *trivial*. I would at least check if there is any such declaration of the class in question. – Cheers and hth. - Alf Nov 09 '14 at 16:39
  • 1
    I'll try to generate a small scale representation of the problem (as the real one, is pretty heavy...) – Itzhak Hasson Nov 09 '14 at 16:39
  • Great! If you do that, you will probably receive a good answer. As the question stands now, it will most likely be down-voted and closed. – Johan Råde Nov 09 '14 at 16:41
  • @Cheersandhth.-Alf - I have 3 forward decleartion of this class. Waht do you mean by trivial destructor ? – Itzhak Hasson Nov 09 '14 at 16:44
  • How did you determine that there was a memory leak? (I ask because Linux has some memory-management behaviors that somewhat resemble memory leaking, but are actually expected behavior) – Jeremy Friesner Nov 09 '14 at 17:15
  • @JeremyFriesner can be easily seen on /proc/[pid]/status VmRSS when this area of the code is running. I'm talking about a serious memory usage rise in there (Hundreds of Mb) – Itzhak Hasson Nov 09 '14 at 17:31
  • trivial destructor is one that does nothing. – Cheers and hth. - Alf Nov 10 '14 at 04:43
  • @Cheersandhth.-Alf in my case a trivial should definitely do the job... – Itzhak Hasson Nov 10 '14 at 07:13
  • doing nothing includes not calling destructors of sub-objects. perhaps your class has a `std::vector` member. for example. it is of course a good idea to leave readers guessing about this rather than posting code. – Cheers and hth. - Alf Nov 10 '14 at 09:39
  • @Cheersandhth.-Alf code sketch added... – Itzhak Hasson Nov 10 '14 at 12:00
  • Well you have `shared_ptr` in there. It requires a destructor call to do its job. Normally that call will come from the `Config` destructor (automatically). But if there is deletion of `Config` via pointer to incomplete class, then you don't necessarily get that destructor call, because the compiler is then free to synthesize a do-nothing `Config` destructor for the occasion. – Cheers and hth. - Alf Nov 10 '14 at 12:08
  • 1
    But please, do not post "roughly like this" code. I am pretty sure that the whole problem fundamentally stems from that kind of approach to things. Details do matter, sometimes very much [(for want of a horseshoe nail, the kingdom fell)](http://en.wikipedia.org/wiki/For_Want_of_a_Nail). – Cheers and hth. - Alf Nov 10 '14 at 12:12

1 Answers1

3

I have seen this exact behavior with incomplete types created by forward declarations and std::auto_ptr.

I believe that the current versions of shared_ptr and unique_ptr have solved this problem by using explicit destructor functions and they will fail to compile if the definition is not visible.

I suspect that your "some other smart pointer" is not doing this, or not doing it correctly. It is tricky to get right. The C++ standards people invented auto_ptr and used it for years before fixing this problem.

Zan Lynx
  • 53,022
  • 10
  • 79
  • 131
  • Does this mean I need to replace all the forward declarations with inlucdes for all auto_ptr's ? I'm gonna have a lot of work replacing them... – Itzhak Hasson Nov 10 '14 at 17:24
  • is this the same problem by the way ? http://stackoverflow.com/questions/1951933/c-auto-ptr-forward-declaration – Itzhak Hasson Nov 10 '14 at 17:24