paradoxresolved
May 5th, 2008, 08:01 PM
I have a number of derived classes, each derived from the same base class that has a static string. If I initialize the string to anything, a memory leak results. Why?
|
Click to See Complete Forum and Search --> : Memory leak with static string paradoxresolved May 5th, 2008, 08:01 PM I have a number of derived classes, each derived from the same base class that has a static string. If I initialize the string to anything, a memory leak results. Why? kempofighter May 5th, 2008, 08:04 PM I have a number of derived classes, each derived from the same base class that has a static string. If I initialize the string to anything, a memory leak results. Why? I have no idea. Post some code that demonstrates the problem. TheCPUWizard May 5th, 2008, 08:20 PM I am willing to bet that you do NOT have a memory leak. There is no hard fast rule as to the order of application exit. Your "leak detector" is probably running BEFORE the statics are being cleared up. To confirm this put a brakpoint of the destructor of the item in question. paradoxresolved May 5th, 2008, 08:25 PM My thinking was somewhere on those lines. I thought perhaps since it was a static variable, and they exist regardless of whether or not any objects exist, they would be destroyed last as the program closes. I wasn't aware that the memory detector might execute too early though. Is there a way to have the memory detector wait until later in the program? TheCPUWizard May 5th, 2008, 09:14 PM If you dont like where the leak detector executs in your compilers runtime, then re-write the runtime. Otherwise simply do as I suggested. exterminator May 6th, 2008, 11:07 AM Without seeing code, it is tough to say anything. TheCPUWizard has a good point as well. Are you sure that the base class has a virtual destructor? Are you sure that you don't have initialization order problem? Or just about any other problem. Can't say without seeing code. paradoxresolved May 6th, 2008, 04:17 PM Oddly enough, the problem seems to be related to Visual C++ (which makes this the wrong forum). I was assigning a value to the static strings in the application's constructor. When I moved it to the application's InitInstance function, the memory leak stopped. I was also having a few other bizarre problems, such as the value of the static string being mysteriously erased shortly after being set, without good reason. This also stopped after moving it to the InitInstance function of the application. Can anyone tell me why this happened? I was under the impression that static variables were global across all appropriate instances. Where I set their values shouldn't matter. exterminator May 6th, 2008, 10:19 PM You will have to show code. Why are you being so mean to us. Posting questions and not the relevant code. However, look at this thread for a specific problem with std::string - don't know if there's a patch but there is a chance you are working without it (or it just isn't there) and you need to take care - Reassignment of basic_string (http://www.codeguru.com/forum/showthread.php?t=403635). This is probably just VC++ 6.0 specific. paradoxresolved May 7th, 2008, 11:20 AM Sorry. I wasn't trying to be mean. I'm being paid to create this code; I'm not allowed to post it. It's not top secret or anything, but my employer is super paranoid. :( Paul McKenzie May 7th, 2008, 11:41 AM Sorry. I wasn't trying to be mean. I'm being paid to create this code; I'm not allowed to post it. It's not top secret or anything, but my employer is super paranoid. :(Then take the time and duplicate the problem with a small sample program. Here is your original problem, as stated in the first post: I have a number of derived classes, each derived from the same base class that has a static string. If I initialize the string to anything, a memory leak results. Why? OK, so create a dummy foo, foo1, foo2, foo3, etc. classes, derived in whatever way, create a static string, and duplicate the memory leak. If the problem can be easily stated, then supposedly the issue can be easily duplicated. If it can't be duplicated, then there is much more than what the original post suggests the issue is. Taking the time to do these steps before posting a question should be followed by anyone. Then the issue of 1) "it's my code from work" never has to be brought up, 2) It saves us time from having to pry code out from the poster, and 3) It more than likely will result in not posting any question here, since taking the time to duplicate it with a smaller example reveals the error to you. Note how the regulars here practically never post questions concerning memory leaks. A good part of the reason is that we follow the steps above, as any good programmer does. The downside is that since we never post questions, new people believe we know the answer to their memory leaks without seeing any code. Of course this is not the case without seeing code that reproduces it. Regards, Paul McKenzie kempofighter May 7th, 2008, 12:16 PM Sorry. I wasn't trying to be mean. I'm being paid to create this code; I'm not allowed to post it. It's not top secret or anything, but my employer is super paranoid. :( Perhaps your employer should switch to decaf. Anyway, as Paul said you could give us a sample. It only takes a few minutes, using the visual studio wizard, to create a simple hello world application or dialog application which reproduces a similar problem. By the way; your employer is paying YOU, not us, to write this code. Nobody on this message board has any stake in your company, that we are aware of and therefore nobody is going to spend hours of their day guessing as to what your problem might be. Show us some code and some professional courtesy and someone might return the favor and help you out. paradoxresolved May 7th, 2008, 09:43 PM Good sirs, I am not trying to waste your time or upset you. I would not have posted this if I hadn't already tried to replicate it in a sample program. I've tried replicating it, but I haven't been able to. The following is basically what my classes are: /* header files */ class FooBase { public: FooBase(); virtual ~FooBase(); static string staticstring; }; class FooDerived : public FooBase { public: FooDerived(); virtual ~FooDerived(); void Initialize(); }; class FooCover { public: FooCover(); virtual ~FooCover(); shared_ptr<FooBase> pBase; FooDerived* pDerived; }; /* source files */ // FooBase.cpp string FooBase::staticstring; FooBase::FooBase() { } FooBase::~FooBase() { } //FooDerived.cpp FooDerived::FooDerived() { } FooDerived::~FooDerived() { } void FooDerived::Initialize() { staticstring = "Who da foo?"; } //FooCover.cpp FooCover::FooCover() { pBase.reset(new FooDerived); pDerived = static_cast<FooDerived*>(pBase.get()); pDerived->Initialize(); } FooCover::~FooCover() { } All the action starts in the App.cpp file, which looks like this: // The one and only theApp. . . FooCover TheFooCover; // FooBase::staticstring value set during FooCover constructor StaticStringLeakApp theApp; // First break point placed here. staticstring exists and is ok. StaticStringLeakApp::StaticStringLeakApp() { int BreakPoint2 = 0; // Second breakpoint. static string still exists } BOOL StaticStringLeakApp::InitInstance() { int BreakPoint3 = 0; // Third breakpoint. static string gone!!! memory leak!!! AfxEnableControlContainer(); //... } In the App.cpp file, I have three breakpoints: 1) The first breakpoint is when the StaticStringLeakApp is declared. By this point, FooCover has already initialized FooDerived, which sets the string. The string exists fine here. No problems. 2) The second breakpoint is in the App constructor. The string still exists and all is well (in both the sample program and in my actual project) 3) The third breakpoint shows the problem. In the sample program (attached), the string still exists and all is still ok, BUT IN MY PROJECT, THE STRING IS GONE!! The only way I can avoid this is to call the derived class's Initialize function at any point AFTER the third breakpoint. I don't understand how a memory leak can even exist since I don't use "new" anywhere. Presumably it is used internally in the string class, but I'm not knowleable of the internals. I also don't know what the computer is doing between App::App() and App::InitInstance(), which appears to be where the problem is occuring. Is something happening between these two functions to inadvertently cause some other aspect of my project to execute? Is there a way to make my debugger pause whenever the string is being changed? That would help to nail this down. EDIT: I should also mention that my project has static integers, doubles, and booleans, which behave normally. The problem is only with the strings. Paul McKenzie May 7th, 2008, 11:58 PM The timing of static initialization and destruction is controlled by the runtime. When an app exits main(), it is indeterminate if static values exist if accessing them from other static objects. That is the C++ explanation. Since this is the non-Visual C++ forum, things like "InitInstance" are just normal member functions that has no meaning to non-MFC persons looking at the code -- a preferable example would be one with traditional C++ with a main() function, and the module names clearly specified. Having said this, I would believe that if you tried to pinpoint where the string is destroyed, it may be educational, but it still won't help you if you kept the string as just a static string. You are more than likely relying on the timing of initialization/deinitialization of statics after the main() has exited, so you'll just be going around in circles trying to fix it (your fix may work sometimes, then it may not work other times). To prevent this, an ugly solution is to keep the static string alive by creating it dynamically with "new" (declare it as a static pointer to a string), so it never gets destroyed by the runtime. On app termination, i.e. when you know you don't need it any more, then you call delete. Regards, Paul McKenzie anantwakode May 8th, 2008, 12:08 AM Hi, Where is the code for reset() and get() functions of base class , and whats the use of these functions ? in your origional application is it base class derived from any other class like CObject or something else ???? some times unloading dll's results in dumping false memory leaks. as the destructor or Memory release code executes after that... by the way which debugger you are using , are you claiming memory leaks on the basis of VS Debugger memory dump. -Anant souldog May 8th, 2008, 03:19 AM Hi, Where is the code for reset() and get() functions of base class , and whats the use of these functions ? in your origional application is it base class derived from any other class like CObject or something else ???? some times unloading dll's results in dumping false memory leaks. as the destructor or Memory release code executes after that... by the way which debugger you are using , are you claiming memory leaks on the basis of VS Debugger memory dump. -Anant reset() and get() are not members of the base class they are members of boost::shared_ptr. pBase is a boost::shared_ptr<FooBase> paradoxresolved May 8th, 2008, 09:24 AM I am using Visual C++ 6.0, but I will soon be switching to a newer version. I imagine it's not the worse IDE in the world, but the debugger is about as helpful as a gun shooting in reverse. There are also some basic macros that are apparently missing (e.g. __FUNC__). Apart from that it has served me well. Anyway, there is unfortunately no equivalent to main() in the dialog-based application. My understanding is that it starts in the App.cpp file, encounters the FooDerived statement, then goes into the App constructor, then goes into the App::InitInstance function. The dialog then gets activated within the App::InitInstance and for the rest of the time the code exists within subfunction called therein. Apparently, initializing static variables prior to the InitInstance function is unpredictable. Correct? Your solution, "ugly" as it may be, appears to be only acceptable one. Thank you Paul. Is there any way I can have this thread moved to the Visual C++ forum? Thank you all. exterminator May 8th, 2008, 10:11 AM Is there any way I can have this thread moved to the Visual C++ forum? Thank you all.Try contacting one of this forum's moderators (look for the names on the bottom of thread list). Send them a PM asking for redirecting it there as well. kempofighter May 8th, 2008, 10:46 AM I find this to be peculiar. BOOL StaticStringLeakApp::InitInstance() { int BreakPoint3 = 0; // Third breakpoint. static string gone!!! memory leak!!! AfxEnableControlContainer(); //... } So you are saying that the application is leaking memory during initialization? The static string is a member of the FooCover class which seems to have a global scope. I thought the memory leak was occuring on exit. The comment in your example seems confusing. I'm not sure I understand the specific problem you are having after reading the comments in your example. paradoxresolved May 8th, 2008, 11:09 AM In the sample program (see attached) the string is still exists and there is NO memory leak at breakpoint 3. All is working as I would expect. In my project, however, the string is gone and a memory leak exists at breakpoint 3. I can't reproduce the leak and it is really annoying me. The fact that a static member has global scope is exactly what's confusing me. The string is disappearing with a memory leak in the MIDDLE of the program between the end of App::App() and App::InitInstance(). No part of my project even contain "new string." I couldn't deliberately cause this error if I wanted to. Anyway, I took Paul's suggestion and dynamically created the static strings, and it seems to have solved the problem. It's ironic that I solved a memory leak by dynamically allocating memory. kempofighter May 8th, 2008, 11:32 AM In the sample program (see attached) the string is still exists and there is NO memory leak at breakpoint 3. All is working as I would expect. In my project, however, the string is gone and a memory leak exists at breakpoint 3. I can't reproduce the leak and it is really annoying me. The fact that a static member has global scope is exactly what's confusing me. The string is disappearing with a memory leak in the MIDDLE of the program between the end of App::App() and App::InitInstance(). No part of my project even contain "new string." I couldn't deliberately cause this error if I wanted to. Anyway, I took Paul's suggestion and dynamically created the static strings, and it seems to have solved the problem. It's ironic that I solved a memory leak by dynamically allocating memory. Thanks for the clarification. CPUWizard's initial reply seemed to indicate that this was a problem during application shutdown, not during initialization. Until you posted your example, I didn't fully understand what type of problem you are having. Also, I wasn't aware that the visual studio debugger printed memory leaks until shutdown. When you say that the "string is gone", I'm not sure what you mean. I don't see how that can be. How exactly did you confirm this? In your example the FooCover object is a global so I don't see how it would get destroyed at that point. So in your example, I do not see a memory leak. I feel your pain; seems like a tough problem but I just don't see how a static variable could disappear in the middle of a program. The idea of a memory leak seems nonsensical at this point. There isn't anything to leak. A leak is when memory exists that cannot be destroyed. Your saying that something is "disappearing". If a leak was occuring that means that the object is still there but there is no way to gain access to it anymore. So I am confused as to why you are classifying your problem as a "memory leak". paradoxresolved May 8th, 2008, 11:47 AM The debugger waits until the end of the program to indicate if there is a memory leak. To the best of my knowledge it does not alert me mid-program; I would be thrilled if I could get that to work. By stating that the string is "gone," I mean that the value of the string returns to "". When the memory leak is reported, however, it tells me the original values. For example, if I set the static string to "This should not leak." the debugger (after exiting the program) will say that I have a memory leak and tell me the memory lost contains "This should not leak." At the breakpoint3, the value of the string is no longer "This should not leak" but rather is "". Since my debugger doesn't tell me exactly when the leak occured, I can only surmise that the two events are one and the same, especially since I never change the value of the static string after initialization. The string should never ever contain "" after I initialize it. If I set the value of the string AFTER InitInstance, I never have a problem. kempofighter May 8th, 2008, 12:48 PM The debugger waits until the end of the program to indicate if there is a memory leak. To the best of my knowledge it does not alert me mid-program; I would be thrilled if I could get that to work. By stating that the string is "gone," I mean that the value of the string returns to "". When the memory leak is reported, however, it tells me the original values. For example, if I set the static string to "This should not leak." the debugger (after exiting the program) will say that I have a memory leak and tell me the memory lost contains "This should not leak." At the breakpoint3, the value of the string is no longer "This should not leak" but rather is "". Since my debugger doesn't tell me exactly when the leak occured, I can only surmise that the two events are one and the same, especially since I never change the value of the static string after initialization. The string should never ever contain "" after I initialize it. If I set the value of the string AFTER InitInstance, I never have a problem. I'm not sure if the memory leak you are referring to has anything to do with whether a static string object has a particular value at some point in the program. I think that these are two different problems, personally. In your example, FooDerived's Initialize() method sets the string to some value (the static object was uninitialized, by default). In the program where your problem is occuring, I'm wondering at what point the string is initialized and if it is possible that somewhere along the lines it is getting reset to "". Or perhaps the string hasn't been initialized even though you think it should have been. Either way, I'm not sure what memory leaks have to do with *that* problem. TheCPUWizard May 8th, 2008, 07:15 PM If it is *not* a bug in the application code, it could also be a memory over-write, this being much more severe. Remember, "in the real world" [on a PC or MAC], the only (non-recurring) leaks that matter those that really require the destructor be called. The memory will always be returned to the system at program exist...But if you have a control program for a nuclear reactor, which you intend to turn of when you exist the program (by implementing it in a destructor), then you could begin to develop a nice glow if that instance ever leaked..... paradoxresolved May 10th, 2008, 12:36 PM TheCPUWizard: heh. . . No nuclear reactor here. Basically, you're saying that this memory leak is not significant because it occurs once, at program exit? Fine by me. :) Kempofighter: I understand your point. The two are not necessarily the same event. It's just frustrating because the string contains the appropriate value at one moment, and then loses it after InitInstance; at the end of the program then the memory leak error shows up. When I set the value of the string after InitInstance, its value remains the same and the memory leak disappears. Highly annoying. Since this problem started, I've added other types of static variables, like shared_ptr<FooBase>. . . the same weirdness occurs. If I set the value of shared_ptr<FooBase> after InitInstance, all is well, and no memory leak shows up. Before InitInstance, the value gets lost and a massive memory leak occurs. Interestingly, simple static variables, like static int, static doubles, and static boolean behave normally regardless of where their values are set. No memory leaks either way. It's just the complex data types and structures that cause problems. I'm convinced that it's MFC mischief. For the moment, I'm just setting their values after InitInstance. Perhaps I'll eventually find the answer, but for now I'm stumped. I requested to have the thread moved to Visual C++ forum, but the moderator said it was better to keep it here since I had too many responses on this forum. If anyone finds out anything, please let me know. Thanks for the help everyone. Paul McKenzie May 10th, 2008, 02:37 PM Interestingly, simple static variables, like static int, static doubles, and static boolean behave normally regardless of where their values are set. No memory leaks either way.Note that pointers are also simple types, which is why using "new" didn't cause a problem. For classes that have user-defined constructors and destructors, there is much more involved. At some point, indeterminate to you, the runtime must construct the global/static object, and again indeteminate to you, the object must have its destructor called after the main() exit point by the runtime. Since the constructor and destructor are actual functions of the global/static object (and for std::string, memory is allocated and deallocated), what you're doing is something that really is different about C++ (as opposed to C), and that is user-defined code running before and after main() executes. That's why the rules are so hard to define when the runtime decides to instantiate a global or static object and when it's time to destroy such an object. There are some general rules about static objects, but only in the context of where they are guaranteed to be initialized after main() has started. I'm convinced that it's MFC mischief.For a Win32 program, the WinMain() is the entry point. Anything outside of WinMain() is basically the same thing as anything outside of main(). So if MFC somehow has placed code outside of the WinMain() entry point, and you're using it in some way (maybe InitInstance(), I don't know) then there is your explanation. So there is a simple explanation, if you take the time to debug the code carefully. By debug, I mean go into MFC and see where WinMain() exits. When you see that happening, then any static objects are basically in a state where you won't be able to guarantee if they will exist. Regards, Paul McKenzie paradoxresolved May 16th, 2008, 10:45 AM I did a search for WinMain in my dialog based program. There were no results. This has contributed to my trouble. I understand your point though. For the moment, I've circumvented the problem by initializing everything after InitInstance, and it seems to work fine. codeguru.com
Copyright Internet.com Inc., All Rights Reserved. |