Removing Large number of objects from vector immediately.

Started by
19 comments, last by SolDirix 10 years, 1 month ago


Every time I allocate all 65,536 Objects to the list

Why on earth are you allocating and deleting 2^16 objects? That seems like an awful lot of items...

Games Like Minecraft will allocate hundreds of thousands of blocks at runtime to RAM, I'm trying to do something similar. 65,536, Objects., Is the total number of blocks in an Chunk in the Minecraft World. I'm Just experimenting with trying to create as many objects as fast as I can, to no avail :/.

View my game dev blog here!

Advertisement

You might be describing the problem of running all those destructors. Some have described it as taking time to empty the trash bins while tearing down a building.

C++ provides a lot of great functionality. One very useful thing the standard library guarantees is that when you start destroying objects their destructors and other cleanup code gets called.

The problem with that: Sometimes you don't want their destructors and other cleanup code to be called.

Many systems (frequently game, but also many business apps) will replace the default memory managers for containers to provide a method to just wipe everything out. No destructors, no cleanup, just release the memory.


This is one of many reasons why professional games tend to throw away the built-in memory manager and use their own. The standard library guarantees are nice, but with insufficient features. Pulling from a global pool can be time consuming, fragmentation of a global pool can be problematic, game-specific alignment needs are more nuanced than the standard specifies, and cleaning up memory when cleanup is unnecessary can be uselessly slow.

But Then how would one build their own memory manager? That Sounds like It May be a lot Of Work. As a Sole independent game developer, Idk if I would go that far, but If you know any resources that could help me learn the basics, do you know of any websites that could help me out?

Oh, and Thnx everyone for the help :3 .

View my game dev blog here!

I'll say again, your problems likely stem from your *pattern* of deletion, rather than the outright number of things being deleted. Depending on what makes up your other objects, though, the deletions themselves might be taking up a significant amount of time. What's in each object? Does it own other memory or resources that need to be freed?

On the topic of custom memory management routines, its not actually all that much work if one knows what they're doing. Its hours or days of work for one developer, depending on the features you want, not weeks or months. Typically what it involves is block allocation, wherein a single object is never allocated, but instead several object's worth at a time are allocated, and some additional book-keeping tracks objects-worth of memory that are unused. These spaces are re-used when "empty" but never deleted unless the entire chunk is freed.

But again, even though custom memory management doesn't need to be complex or scary, all signs point towards poor usage patterns IMO (or perhaps unrealistic expectations, depending on what destructors do), not to the kinds of problems that a custom memory manager would solve.

throw table_exception("(? ???)? ? ???");

Games Like Minecraft will allocate hundreds of thousands of blocks at runtime to RAM, I'm trying to do something similar. 65,536, Objects., Is the total number of blocks in an Chunk in the Minecraft World. I'm Just experimenting with trying to create as many objects as fast as I can, to no avail :/.

I highly doubt that minecraft allocates 2^16 separate objects to represent a single 16*16*256 chunk of cubes.

It would generally be stored as a single 2^16 element array of bytes, where each byte represents the type of a single block (or zero for an empty block). For rendering you would walk over this structure and generate a suitable vertex buffer - which again, is a flat array of vertices.

Moral of the story: allocating many thousands of small objects is almost always something which should be avoided.

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]

I suppose next time I should read your code :)

So, I see you're not explicitly deleting individual elements in a loop, however, you still need to understand that the destructor is being called for each object when you delete the list. For these particular objects, the destructor is simple since you've just got a POD type. But the problem is that you're hitting the built-in memory manager's deallocator 65k times -- since memory is a shared resource, taking or returning memory to the pool can be non-trivial.

So, I take it back. This probably is the kind of problem that a pooled memory manager would benefit you. Conceptually, think of it as allocating a raw array of 65k objects, and then creating shared-pointers to those objects within it. Now, if the destructor for those items does work you still need to call them but you don't need to deallocate the memory -- but if they do no work, then you can just reuse those element-spaces that are dis-used, and deallocate that huge array when you're done with all of them. If you abstract that, and throw in a little book-keeping you end up with a pooled memory manager, though usually you will use smaller chunks.

All that being said, understand that you're allocating 64 MB of data here, in small chunks, and this is what causes you to hit the standard deallocator so much-- and its probably taking locks and crossing into kernel-space every time. That's not cheap.

throw table_exception("(? ???)? ? ???");

Well, Every time I allocate all 65,536 Objects to the list, it happens very quickly, however deleting the list actually takes around 5 seconds, and I don't know why sad.png.

I switched to release mode and disables Secure Scl, and it improved, but not by much.

Since you mention SCL I assume you are using Visual Studio. Are you running your program with F5 or with Ctrl+F5? It is not the same.

When you run your program with Visual Studio hooked to your process memory allocation / deallocation is far slower. (EVEN if you are in Release mode). This is thanks to the so-called DEBUG HEAP smile.png

I have a ~15 seconds delay (Visual Studio 2012, Release Mode, Win64) when running with F5, but the code runs instantaneously when using Ctrl+F5 (AKA: running the program process independently of VS).

Look at this question of Stack Overflow for more information: http://stackoverflow.com/questions/6486282/set-no-debug-heap (it is tagged as C#... but it is not a C# question).

PS: Regardless, using a custom stack memory allocator (http://molecularmusings.wordpress.com/2012/08/27/memory-allocation-strategies-a-stack-like-lifo-allocator/) might be a good optimization is you see that you have a bottleneck here. But as always, MEASURE before optimizing. Remember that "optimization is the root of all evil (Donnald Knuth)" ;)

“We should forget about small efficiencies, say about 97% of the time; premature optimization is the root of all evil” - Donald E. Knuth, Structured Programming with go to Statements

"First you learn the value of abstraction, then you learn the cost of abstraction, then you're ready to engineer" - Ken Beck, Twitter

Well, I tried out what the OP said, and I'll be damned if he wasn't correct. Calling delete 65000 times does indeed take about 5 seconds on my system. I'm actually somewhat surprised, but when reality differs from your thoughts, I find reality is usually correct.

However, calling delete[] on a 65000 long array is near instantaneous. Also, calling std::vector::resize( 0 ) on a vector of objects (not pointers!) is also super fast. So, for the OP, I would advise storing objects directly in a std::vector, rather than pointers. Only if that is impossible should you look into the more complicated allocation pooling solutions.

Geoff

Code:


// ConsoleApplication1.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <vector>

#define FOONUM 65000

static int iConstructor = 0;
static int iDestructor = 0;
class CFoo
{
public:
    CFoo() { iConstructor++; }
    ~CFoo() { iDestructor++; }

    char chFoo[ 256 ];
};

int _tmain(int argc, _TCHAR* argv[])
{
    CFoo *fooArray[ FOONUM ];

    int i;
    for( i = 0; i < FOONUM; i++ )
    {
        fooArray[ i ] = new CFoo;
    }

    for( i = 0; i < FOONUM; i++ )
    {
        delete fooArray[ i ];
    }

    CFoo *fooArray2;
    fooArray2 = new CFoo[ FOONUM ];

    delete[] fooArray2;

    std::vector< CFoo > fooArray3;
    fooArray3.resize( FOONUM );

    fooArray3.resize( 0 );

return 0;
}

Well, I tried out what the OP said, and I'll be damned if he wasn't correct. Calling delete 65000 times does indeed take about 5 seconds on my system. I'm actually somewhat surprised, but when reality differs from your thoughts, I find reality is usually correct.

However, calling delete[] on a 65000 long array is near instantaneous. Also, calling std::vector::resize( 0 ) on a vector of objects (not pointers!) is also super fast. So, for the OP, I would advise storing objects directly in a std::vector, rather than pointers. Only if that is impossible should you look into the more complicated allocation pooling solutions.

Well, today is my day for not believing people! Someone else said "run without debugging, and it will be much faster". Sounded like hogwash to me. But, when I did that exact experiment, it was correct! So, OP, you may not have a "real world" issue at all. And, Javier Meseguer de Paz, apologies for not believing you at first!

Geoff


Since you mention SCL I assume you are using Visual Studio. Are you running your program with F5 or with Ctrl+F5?

This. I run the OPs code in debug mode, and it does take several seconds to delete the vector. Run it without debugging and everything is apparently instantaneous. Would have to add in some timing code to see how long everything takes.

No, you really don't need to time anything. (As a rule, yes - you should). But in this case, Javier is right. The calls to free memory underlying the delete calls are what's taking forever, and it's because the debug heap is enabled. The debug heap verifies the integrity of the entire heap (by ensuring that every allocation's bookkeeping information is still correct) on EVERY free call. Programs that thrash the system (win32) heap run incredibly slowly with the debug heap enabled, period.

This topic is closed to new replies.

Advertisement