Allegro.cc - Online Community

Allegro.cc Forums » Off-Topic Ordeals » My memory problems are over

This thread is locked; no one can reply to it. rss feed Print
 1   2 
My memory problems are over
HoHo
Member #4,534
April 2004
avatar

Quote:

say, your kernel or some math function that is called thousands of times

For performance reasons those things should avoid dynamic memory as plague anyway or at least use object pools

__________
In theory, there is no difference between theory and practice. But, in practice, there is - Jan L.A. van de Snepscheut
MMORPG's...Many Men Online Role Playing Girls - Radagar
"Is Java REALLY slower? Does STL really bloat your exes? Find out with your friendly host, HoHo, and his benchmarking machine!" - Jakub Wasilewski

axilmar
Member #1,204
April 2001

SiegeLord said:

Heap is not meant to be used in that way, you are supposed to allocate and deallocate it very very sparingly.

Not if the application is big and requirements change often.

Goalie Ca said:

Once i get this paperwork done i will sit down and study the papers on the boehm gc.

It's very clever. It takes into advantage the virtual memory system, and allocates/deallocates memory in blazing speed. In my machine, 100,000 objects are freed in less than a millisecond. With 10 threads allocating 100,000 objects, it takes less than a second to finish the program, and my CPU is not even dual core.

Goalie Ca said:

Mostly if i want "memory woes gone" then i use a language that has a gc and has other nice things as well.

Well, it all depends on the requirements of the software. The new project I am about to do must be written in c++, and the deadlines are very strict. I spend 4 months debugging the previous project (120,000 lines of c++ code), and it still have bugs, so I am not doing the same mistake twice.

Goalie Ca said:

Auto_ptr's have ownership and they are fast

And they have the unfortunate "advantage" of tranferring ownership when they are assigned...which means they can't be used in anything but simple stack jobs. I think the purpose of auto_ptr was to have a scoped ptr, but the semantics are not correct.

HoHo said:

I wonder if I'm missing something but why do people use that much manual memory management?

It depends on the complexity of the program. For small programs, manual memory management is ok. For big complex applications, it's a nightmare. Manual memory management simply does not scale.

HoHo said:

Those programs do not use QT, with QT things would be even simpler even though there would be a lot more manual memory allocations there. QT FTW

Qt is good, but it does not use gc. I am planning to use QObject a lot in the new project (because I need to implement a model-view-controller application), but it's going to be complex, so I am going to hack the Qt sources to use Boehm's gc.

Carrus85 said:

Encourages lazier programming in general(good for quick hack-up programs, bad when the runtime performance of an algorithm is very, very important

Not really. Premature optimization is the root of most evil in quite a few cases. It's easier to identify hot spots using a profiler than trying to manage a memory problem.

Human resources are much more expensive than machines, so if there is a performance problem due to lazy programming, a good option is to throw more hardware at it.

Carrus85 said:

Also encourages "static abuse" in a lot of GC-able languages (for example, concatenating two strings together in Java creates a whole new string, because strings are immutable; major performance bottleneck for those who don't watch their step).

In current Java implementations, string concatenations within an expression is turned to a printf-style expression using StringBuffer.

You have to remember that in Java, allocation is very cheap: the heap pointer is simply incremented. It's like stack allocation.

In c++, although the Boehm's gc is not as fast as Java's (because it's a conservative gc), performance is good (better in some cases) because many objects can be allocated on the stack.

Carrus85 said:

Adds a degree of non-determinism in program runtime

Boehm's gc is incremental (GC_enable_incremental), and it usually does a very good job.

Carrus85 said:

Sometimes you just want control of the memory allocations. (Memory pools are ridiculously fast for allocating a lot of small objects of the same type, for example).

That's why I am not leaving c++ anytime soon.

Carrus85 said:

Doesn't work with RAII (if you must allocate everything on the heap, ala java). And no, finalizers are not a substitute for RAII due to their non-deterministic execution; you know the finalizer will run, but you don't know when it will run, which can be a huge problem if you expect it to run immediately after going out of scope. (Thus, you end up having to finally blocks and other garbage to clean up after yourself, which isn't as clean as RAII.)

I don't know why people keep saying that (I am not saying it for you, as you seem to recognize the advantage of gc in c++). It's not true in c++.

For example, you can allocate your garbage-collected objects on the stack:

File file("temp.txt");

Or you can allocate them on the heap, and use a helper class which does the cleanup. For example:

Temp<File> temp(new File);

In both cases, RAII works beautifully.

It's too bad that other languages don't have stack allocation.

Quote:

Now, that given, the description of Boehm's gc via GC_malloc, it should be possible to just globally override new and delete and use them (assuming GC_malloc doesn't take any other strange arguments or have screwy side effects, as well as a GC_free existing somewhere). This would give you a really interesting benefit, in C++ in particular; you could use RAII where you want, use regular old new for everything else, and get garbage collection for free (in theory). I'd have to look up specifics and run some tests, though.

If you use another library which globally overrides new and delete, then you are out of lack. MFC does that, and it's a pain in the a$$ (and a major source of memory management problems).

One stupid design decision in c++ is that global new and delete operations can not be part of a namespace...it does not allow to put a bunch of classes in a namespace, then declare new and delete once for all of the namespace.

Another stupid decision in c++ is that new and delete operators don't have access to the type of the allocated object, so it's not possible to have a base class with a garbage-collected new and delete that is not polymorphic.

Despite all this, give me c++ with gc anyday over Java and the alternatives. Templates and stack allocation overshadow any disadvantages.

HoHo
Member #4,534
April 2004
avatar

Quote:

Qt is good, but it does not use gc

And unless I've completely missed something then it doesn't need to, at least not for anything they themselves provide. Just create the stuff with new and forget about it :)

Quote:

Manual memory management simply does not scale.

I know, that's why I said avoid it completely by using tried and tested containers for objects :P

__________
In theory, there is no difference between theory and practice. But, in practice, there is - Jan L.A. van de Snepscheut
MMORPG's...Many Men Online Role Playing Girls - Radagar
"Is Java REALLY slower? Does STL really bloat your exes? Find out with your friendly host, HoHo, and his benchmarking machine!" - Jakub Wasilewski

axilmar
Member #1,204
April 2001

Quote:

And unless I've completely missed something then it doesn't need to, at least not for anything they themselves provide. Just create the stuff with new and forget about it :)

Well, it's not that simple.

For example, take QValidator objects. You insert them into QLineEdit objects like this:

Quote:

QLineEdit *lineEdit = new QLineEdit(bla bla);
lineEdit->setValidator(new QIntValidator(min, max));

The above code just introduced a memory leak!

The correct way to do it is:

Quote:

lineEdit->setValidator(new QIntValidator(min, max, lineEdit));

If you don't pass the owner QObject in the constructor, the validator object will simply never be deleted.

But what if you want to set a new validator to the line edit? You do the following:

Quote:

lineEdit->setValidator(new QDoubleValidator(min, max, lineEdit));

But you introduced another memory leak! the previous validator will be there, waiting to be deleted, but it will never be deleted, and even worse, you can't have a pointer to it (unless you traverse the children objects of line edit and find it and delete it)!

Another example is QPopup and QPushButton:

Quote:

QPushButton *btn = new QPushButton(bla bla);
QPopupMenu *popup = new QPopupMenu();
bla bla fill popup with menu items
btn->setPopup(popup);

The above again introduces a memory leak, because the popup menu will never be deleted.

Say now that you make the popup a child of the dialog it appears into:

Quote:

QPopupMenu *popup = new QPopupMenu(dialog1);

Now the menu will be destroyed when the dialog is destroyed.

Suppose now 3 months pass and another member of your time comes along and decides to reuse the popup menu. He does something like this:

Quote:

QPushButton *btn = new QPushButton("a", dialog2);
btn->setPopup(popupMenu);

Guess what: we don't have a memory leak, but we have a DANGLING POINTER! which is even more dangerous.

Suppose the user opens 'dialog1' and 'dialog2', then closes 'dialog1'. The popup menu will be destroyed, but nothing will happen. The user will not see it if the memory block previously occupied by 'popup' is not reused in anything else. The user might even use the popup menu as it is, even if the popup menu will have been deleted!

Suppose that another object takes over the memory block occupied the popup menu. The object is 'Account', and its vtable has a function 'deleteAccount' at offset N.

As the user uses the popup menu of 'dialog2', an account is deleted! Because the function 'deleteAccount' was invoked instead of 'close()' or something else the menu was supposed to do!

You see, it's not that simple. The only viable solution for big complex projects with lots of developers is garbage collection.

Steve++
Member #1,816
January 2002

I doubt any of you are writing anything where the choice of memory management strategy will make or break your project with respect to performance. One of the biggest reasons I use Java is because it takes care of freeing memory so I don't have to clutter my code with deletes. There are so many more ways in which Java improves developer performance over C++ in leaps and bounds.

I would recommend all serious C++ game programmers take the time to get to know Java. The learning curve is small because the language is simple and tidy, so you can get up to speed in no time. The niche of Java game developers is growing and there are some excellent game libraries such as jMonkeyEngine and LWJGL. And the standard API comes with a ton of stuff; just imagine Allegro as being a tiny subset of it.

As far as performance goes, memory allocation and method calls come very cheap. The garbage collector performs extremely well. The standard API comes with a very fast I/O library (in many cases I/O can bypass the JVM entirely using memory mapping) and if you have a piece of code that really must be optimized, you can write it in C or C++ and use it via JNI.

Carrus85
Member #2,633
August 2002
avatar

Steve++ said:

I would recommend all serious C++ game programmers take the time to get to know Java. The learning curve is small because the language is simple and tidy, so you can get up to speed in no time. The niche of Java game developers is growing and there are some excellent game libraries such as jMonkeyEngine and LWJGL. And the standard API comes with a ton of stuff; just imagine Allegro as being a tiny subset of it.

Java is wonderful, with one minor problem; the language is WAY to verbose for my taste. Java follows the "language designer knows best, so lets shackle the programmer" methodology (for example, no operator overloading is allowed. While this is okay, it just adds a lot of clutter when you actually want to overload an operator (not when you are doing funky "lets make + behave like *" crap, but when you are writing, say, a complex number class...) Checked exceptions are another annoying design problem; far to often I see programmers wrapping the checked exception in RuntimeException to get around it. Not that I recommend doing this, it is just way to often I find myself having to just pass on checked exceptions because I cannot do anything about it (and after a while, I get kinda tired of find, for example, that an interface won't let me throw an exception of a particular type, or other garbage)) instead of the "programmer knows best." Look, if I as a programmer actually want to overload an operator, just get out of my way and let me do it. In other words, the signal to noise ratio in a lot of java code I read seems to be annoyingly high for my taste.

Quote:

Quote:
Manual memory management simply does not scale.
I know, that's why I said avoid it completely by using tried and tested containers for objects :P

Agreed. Although, with proper encapsulation, memory management scales much further than trying to manage it all by hand (assuming everybody knows who should own the memory to an item, which can be a large assumption at times...).

Goalie Ca
Member #2,579
July 2002
avatar

For a project like firefox, garbage collection is the only solution. There is just way too much going on for any mere mortal to comprehend. In almost all of my projects memory management is not a problem (except when i need to allocate more than 25GB for super large arrays/matrices). Smart pointers are as complicated as i need and even then they are only needed on ocassion. Long-live stack allocation!

A language like java is anti-productive. Extreme verbosity is required without getting anything from it. Exception handling is as big of a mystery as object.kick(ball) or ball.getHit(object).

I'm all for functional programming. Remove all state except where absolutely necessary. Functional languages are short and sweet. Lazy evaluation is even nicer than garbage collection.

-------------
Bah weep granah weep nini bong!

Steve++
Member #1,816
January 2002

Quote:

A language like java is anti-productive. Extreme verbosity is required without getting anything from it.

Java is hardly verbose. I'm sure you can show me some contrived examples and call it proof that Java is verbose. In the real world, a lot less code does a lot more work with a lot less bugs when compared to equivalent C++ projects. You have to realise that Java is an improvement on C++, not the other way around. There are very good reasons it excludes a lot of C++ features. And if you really must use operator overloading, mix it with a bit of Groovy, which overloads operators in a much more readable way than C++.

Tobias Dammers
Member #2,604
August 2002
avatar

Quote:

Java is wonderful, with one minor problem; the language is WAY to verbose for my taste. Java follows the "language designer knows best, so lets shackle the programmer" methodology (for example, no operator overloading is allowed. While this is okay, it just adds a lot of clutter when you actually want to overload an operator (not when you are doing funky "lets make + behave like *" crap, but when you are writing, say, a complex number class...) Checked exceptions are another annoying design problem; far to often I see programmers wrapping the checked exception in RuntimeException to get around it. Not that I recommend doing this, it is just way to often I find myself having to just pass on checked exceptions because I cannot do anything about it (and after a while, I get kinda tired of find, for example, that an interface won't let me throw an exception of a particular type, or other garbage)) instead of the "programmer knows best." Look, if I as a programmer actually want to overload an operator, just get out of my way and let me do it. In other words, the signal to noise ratio in a lot of java code I read seems to be annoyingly high for my taste.

Very well-worded. I find the exception stuff to be the most annoying feature ever. More often than not, there's nothing you can do about a certain exception, and you just want to pass it through and stop the program.

---
Me make music: Triofobie
---
"We need Tobias and his awesome trombone, too." - Johan Halmén

axilmar
Member #1,204
April 2001

Quote:

ava is wonderful, with one minor problem; the language is WAY to verbose for my taste. Java follows the "language designer knows best, so lets shackle the programmer" methodology (for example, no operator overloading is allowed. While this is okay, it just adds a lot of clutter when you actually want to overload an operator (not when you are doing funky "lets make + behave like *" crap, but when you are writing, say, a complex number class...) Checked exceptions are another annoying design problem; far to often I see programmers wrapping the checked exception in RuntimeException to get around it. Not that I recommend doing this, it is just way to often I find myself having to just pass on checked exceptions because I cannot do anything about it (and after a while, I get kinda tired of find, for example, that an interface won't let me throw an exception of a particular type, or other garbage)) instead of the "programmer knows best." Look, if I as a programmer actually want to overload an operator, just get out of my way and let me do it. In other words, the signal to noise ratio in a lot of java code I read seems to be annoyingly high for my taste.
Very well-worded. I find the exception stuff to be the most annoying feature ever. More often than not, there's nothing you can do about a certain exception, and you just want to pass it through and stop the program.

That's why c++ with garbage collection is better than Java! :-)

EDIT:

According to Hans Boehm, his gc allocates blocks of the same size from the same page, so finding blocks is as simple as dividing the pointer's address (the page offset part, actually) with the block size for that page. It's very very fast, I would dare say faster than manual allocation.

EDIT2:

The D programming language also uses Boehm's gc.

 1   2 


Go to: