#1
  1. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jul 2003
    Location
    Brisbane, Australia
    Posts
    12
    Rep Power
    0

    Memory Management


    Howdy all,

    Just a quick question regarding people's opinions on memory management - i.e. what, in your opinion, is the best way to manage dynamically allocated memory?

    I've used reference counting (via COM style AddRef/ReleaseRef methods) and boost style smart pointers (which basically do the same thing, without compromising the interface of the user classes), but the latter falls apart with circular references while the former is often error prone and - although it's possible to work around circular references - its often awkward to do so.

    Aggregation works well for me, but the problem comes when I share a dynamically allocated object amongst several other objects - obviously, because there's no centralised point where something can be safely deleted.

    Would it make sense to use some whacky combination of these or am I missing something? :)

    - TL
  2. #2
  3. No Profile Picture
    Offensive Member
    Devshed Novice (500 - 999 posts)

    Join Date
    Oct 2002
    Location
    in the perfect world
    Posts
    622
    Rep Power
    28
    I have a simple memory management ideal.

    If a funtion allocates memory, it frees it before the function returns. This especially applies to GDI memory.

    Otherwise the memory has scope for the whole app, being tested at close and freed as needed.
    For debugging, I keep a count of how much I have allocated and freed. If these do not match I know I have a leak.
    The essence of Christianity is told us in the Garden of Eden history. The fruit that was forbidden was on the Tree of Knowledge. The subtext is, All the suffering you have is because you wanted to find out what was going on. You could be in the Garden of Eden if you had just kept your f***ing mouth shut and hadn't asked any questions.

    Frank Zappa
  4. #3
  5. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jul 2003
    Location
    Brisbane, Australia
    Posts
    12
    Rep Power
    0
    Hi TechNoFear,

    If you're developing in Windows, a better idea would be to use the HeapCreate/Alloc/Free/Destroy functions while overloading the default new and delete operators.

    Then, you can use atexit to hook a last-minute function to call HeapWalk to iterate over the blocks of still-allocated memory on your heap, and then finally destroy the said heap just before exit.

    That way you know the size of each individual memory leak, how many leaks you have and the address in-memory as to where it was allocated.

    Further improvements on this (involving macros) will let you track memory leaks down to the line and file at which memory was allocated. I've never actually tried to do this, but I know it's possible - the trick is keeping track of the file/line pairs, because in order to track them, you need dynamic memory - but your application will falsely report your file/line pairs as memory leaks (the age-old chicken/egg problem) as they need to be stored somewhere too!

    However, there's always malloc and free, so you could implement your own linked list using C style memory allocation to work around it.

    Regards,
    Tom L
  6. #4
  7. No Profile Picture
    Offensive Member
    Devshed Novice (500 - 999 posts)

    Join Date
    Oct 2002
    Location
    in the perfect world
    Posts
    622
    Rep Power
    28
    >>while overloading the default new and delete operators.

    Assumes I'm using C++ not pure WIN32 in C.


    >>so you could implement your own linked list using C style memory allocation to work around it.

    As I said I keep a track of the memory if in debug inc line numbers and file.

    >>there's always malloc and free,

    I prefer GlobalAlloc() and/or VirtualAlloc() depending on target OS, free memory and memory block size.
    The essence of Christianity is told us in the Garden of Eden history. The fruit that was forbidden was on the Tree of Knowledge. The subtext is, All the suffering you have is because you wanted to find out what was going on. You could be in the Garden of Eden if you had just kept your f***ing mouth shut and hadn't asked any questions.

    Frank Zappa
  8. #5
  9. No Profile Picture
    Junior Member
    Devshed Newbie (0 - 499 posts)

    Join Date
    Feb 2003
    Location
    New Zealand
    Posts
    28
    Rep Power
    0
    Just free the memory as soon as you dont need it. No need to get special and put it in any pointer wrapper.
  10. #6
  11. Left due to despotic ad-min
    Devshed Beginner (1000 - 1499 posts)

    Join Date
    Jun 2003
    Posts
    1,044
    Rep Power
    14
    Unfortunately, there is no "best" method of managing memory allocation and deallocation. There are trade-offs. The simple "a function is responsible for deallocating resources it allocates" does not work in large systems (and also doesn't work if an exception is thrown).

    For a single threaded C++ program, the best technique is to make a single object (or class) always reponsible for cleaning up the resources it uses (memory, file handles, etc). By that I mean;

    1) Constructors allocate the resource when the object is created.
    2) Any function that needs to reallocate the resource (eg resize the allocated memory) goes through the following sequence

    a) Create a copy of the current object with the newly allocated resource and copy current values into the new as required.
    b) Use an exception-safe swap function to swap resources between the current object and it's copy.

    3) The destructor of the object releases the resource.

    This has a number of advantages, including exception safety.

    In C++, standard container classes such as std::vector should be used rather than dynamically allocating arrays. Why? Because the standard containers are guaranteed to do something like the above. i.e. they won't cause memory leaks unless the object they contained is particularly badly behaved. Among other things a "well behaved" object is essentially one that has sensible copy semantics (eg it's copy constructor actually creates a copy, the assignment operator doesn't do non-intuitive things, destructors never throw an exception).

    If you need to dynamically create a single object, hand it off to a std::auto_ptr. auto_ptr will then release the object when the auto_ptr is destroyed. One caveat: auto_ptr can't be elements of the standard container classes. The boost library contains other smart pointers that --- depending on what you're trying to do --- may be more applicable than auto_ptr.

    Reference counting should be used if multiple objects (or functions) need to reference the same dynamically allocated memory. Essentially, provide a wrapper class that deallocates when the reference count falls to zero. The problem with this comes in if some function forgets to increment or decrement a reference count, so this technique is often best combined with what I called the "best" technique above (i.e. have constructors increment the reference count on a reference counted pointer, destructors decrement it, etc). Another problem with reference counting is that it is possible to have circular references (eg A holds a reference to B which holds a reference to A) which basically means none of the circularly referenced objects will ever be released. There are reference counted smart pointer types in the boost library.

    If you need to pass resources between threads (obviously something that the C++ standard doesn't support) you definitely need some form or reference counting. The reference counting scheme must be thread safe; achieving that is expensive, so thread-safe reference counting should not be used unless you know your program will be multithreaded and will pass references to objects between threads.

    There are garbage collection libraries out there (eg Hans Boehm collectors) that can be plugged into any program. These guarantee --- like Java --- that memory will be released *sometime*. The problem with these is that their implementation is highly compiler dependent, and (just as in Java) the scheme they use to release memory is difficult to control. For example, the "mark and sweep" approach to detecting used and unused memory can effectively halt a running program while it's running; that is obviously undesirable for programs with fixed timing constraints (eg hard realtime). It can also be quite a while before memory is released.

    I'm sure there are other ways of managing memory that I've forgotten :-)
  12. #7
  13. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Aug 2003
    Location
    Zagreb, Croatia
    Posts
    15
    Rep Power
    0
    Originally posted by TechNoFear
    I prefer GlobalAlloc() and/or VirtualAlloc() depending on target OS,
    free memory and memory block size.
    Could you please say some more about this?

    I've been thinking about these and HeapAlloc() too, but I could not
    find any good guidance how to choose. Like, in Petzold you can find
    a sentence going like this - "you only need to use GlobalAlloc if you
    don't want your memory to get fragmented."
    Huh? Please raise hands those who want your memory fragmented!

    In Win32 SuperBible they are using mostly HeapAlloc in their
    examples, and Petzold is mostly using simple malloc.

    So, can you give some examples of what aru you using and where.
    (Like for GDI objects, clipboard, metafiles, data to be exchanged with your
    own dll, huge buffers that last for longer while, etc..., how do you
    use LockHandle, etc, etc.)

    Delf
  14. #8
  15. No Profile Picture
    Offensive Member
    Devshed Novice (500 - 999 posts)

    Join Date
    Oct 2002
    Location
    in the perfect world
    Posts
    622
    Rep Power
    28
    My personal choices;

    Speed important? -> Heap function

    Size greater than 4Mb on NT based MS OS (or 2Mb on Win9x, ME)? -> use heap

    Need some other features? -> use heap or Virtual

    else use GlobalAlloc.

    Code:
    HGLOBAL         hMem=NULL;
    MY_STRUCT    *pMyArray=NULL;
    int                   iRecords=100;
    
    hMem = GlobalAlloc(GHND , iRecords * sizeof(MY_STRUCT));
    //error check hMem != NULL
    pMyArray = (MY_STRUCT) GlobalLock(hMem);
    
    // use array
    
    hMem= GlobalHandle(pMyArray);
    GlobalFree( hMem);
    //error check hMem == NULL
    The essence of Christianity is told us in the Garden of Eden history. The fruit that was forbidden was on the Tree of Knowledge. The subtext is, All the suffering you have is because you wanted to find out what was going on. You could be in the Garden of Eden if you had just kept your f***ing mouth shut and hadn't asked any questions.

    Frank Zappa
  16. #9
  17. Banned ;)
    Devshed Supreme Being (6500+ posts)

    Join Date
    Nov 2001
    Location
    Woodland Hills, Los Angeles County, California, USA
    Posts
    9,643
    Rep Power
    4248
    Quote from Microsoft regarding GlobalAlloc() and HeapAlloc() vs. VirtualAlloc():
    "Windows Me/98/95: The heap managers are designed for memory blocks smaller than four megabytes. If you expect your memory blocks to be larger than one or two megabytes, you can avoid significant performance degradation by using the VirtualAlloc or VirtualAllocEx function instead."

    http://msdn.microsoft.com/library/de...lobalalloc.asp
    http://msdn.microsoft.com/library/de.../heapalloc.asp
    Up the Irons
    What Would Jimi Do? Smash amps. Burn guitar. Take the groupies home.
    "Death Before Dishonour, my Friends!!" - Bruce D ickinson, Iron Maiden Aug 20, 2005 @ OzzFest
    Down with Sharon Osbourne

    "I wouldn't hire a butcher to fix my car. I also wouldn't hire a marketing firm to build my website." - Nilpo
  18. #10
  19. No Profile Picture
    Offensive Member
    Devshed Novice (500 - 999 posts)

    Join Date
    Oct 2002
    Location
    in the perfect world
    Posts
    622
    Rep Power
    28
    Sorry, a typo, as Scorpions points out

    >>Size greater than 4Mb on NT based MS OS (or 2Mb on Win9x, ME)? -> use heap

    should be

    Size greater than 4Mb on NT based MS OS (or 2Mb on Win9x, ME)? -> use Virtual
    The essence of Christianity is told us in the Garden of Eden history. The fruit that was forbidden was on the Tree of Knowledge. The subtext is, All the suffering you have is because you wanted to find out what was going on. You could be in the Garden of Eden if you had just kept your f***ing mouth shut and hadn't asked any questions.

    Frank Zappa

IMN logo majestic logo threadwatch logo seochat tools logo