Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » Allgro Memory Effeciency

Credits go to Jonatan Hedborg for helping out!
This thread is locked; no one can reply to it. rss feed Print
Allgro Memory Effeciency
InfiniteLoop
Member #8,434
March 2007

Hello all,

I have noticed that I have programs written with Allegro that crash after allotting too much memory. I thought that this was odd because I used all proper delete and destroy statements. So I made a little test program:

1#include <allegro.h>
2 
3void main()
4{
5 allegro_init();
6 
7 BITMAP *ptrBitmap;
8 
9 while(1 == 1)
10 {
11 ptrBitmap = new BITMAP;
12 ptrBitmap = create_bitmap(600, 600);
13 
14 destroy_bitmap(ptrBitmap);
15 }
16 
17 allegro_exit();
18}
19END_OF_MAIN()

After I ran this, I watched my system memory quickly becoming used up and unreleased. Is there any way to better manage memory than the destroy_bitmap() function? Am I doing something wrong? Thank you.

EDIT* Also, I tried using delete on my pointer after destroy but it throws an exception, so that isn't it.

Kris Asick
Member #1,424
July 2001

Remove this line:

ptrBitmap = new BITMAP;

It is the cause of all your problems.

--- Kris Asick (Gemini)
--- http://www.pixelships.com

--- Kris Asick (Gemini)
--- http://www.pixelships.com

InfiniteLoop
Member #8,434
March 2007

Well, good call. That certainly fixed the problem of my test program. I am still at odds though since I only use the "new" operator in my actual game once and I am pretty sure I handle it right. I pose another query then, how would you go about deleting/destroying this:

1BITMAP *temp = load_bitmap(pic.c_str(), NULL);
2 
3 //create the arrays
4 ptrTile = new BITMAP *[rc*rc];
5 ptrGrid = new BITMAP **[rc];
6 ptrSolution = new BITMAP**[rc];
7 for(int i = 0; i < rc; i++)
8 {
9 ptrGrid<i> = new BITMAP*[rc];
10 ptrSolution<i> = new BITMAP*[rc];
11 }
12 
13 //initialize the arrays to NULL
14 for(int i = 0; i < rc; i++)
15 {
16 for(int j = 0; j < rc; j++)
17 {
18 ptrTile[(i+j*rc)] = NULL;
19 ptrSolution<i>[j] = NULL;
20 ptrGrid<i>[j] = NULL;
21 }
22 }
23 
24 //fill the tile array
25 for(int i = 0; i < (rc * rc - 1); i++)
26 ptrTile<i> = grabFrame(temp, challenge, challenge, 0, 0, rc, i);
27 
28 //create the solution grid for the end of game test
29 for(int i = 0; i < rc; i++)
30 {
31 for(int j = 0; j < rc; j++)
32 {
33 ptrSolution<i>[j] = ptrTile[(i+j*rc)];
34 ptrGrid<i>[j] = ptrSolution<i>[j];
35 }
36 }
37 
38 //clean the temp bitmap
39 destroy_bitmap(temp);

Essentially what is happening is that I have to make two 2D arrays and one 1D array dynamically since I wont know the size. Then I assign bitmaps to them.
Since my dynamic arrays also contain bitmap *, I am curious as to the proper way to clean it. Any help would be great.

Kris Asick
Member #1,424
July 2001

stares blankly at that code

You sir, are abusing your pointers! :o

Basically, I have two tips for you that should help you figure this out yourself:

1. Always delete pointers in the opposite order you created them in with new.

2. Allegro's bitmap loading, creation, and destruction routines do all the memory allocation for you. (So you should never call new and delete on BITMAP objects.) Same goes for any other Allegro routines that have a destroy command. (Datafiles, samples and fonts spring to mind, there might be others.)

--- Kris Asick (Gemini)
--- http://www.pixelships.com

--- Kris Asick (Gemini)
--- http://www.pixelships.com

tobing
Member #5,213
November 2004
avatar

You have to specify which of these should be responsible for holding the allocated memory. I guess that grabFrame allocates the bitmap it returns? Then it would seem that ptrTile should be responsible for memory, because ptrSolution and ptrGrid only have pointers to memory that's already held by ptrTile, is that right? So, if that's what I guess, then only ptrTile should destroy the bitmap and delete the allocated memory, the other arrays should just be freed what they have allocated themselves before.

I would put ptrSolution and ptrGrid in a class (they seem to be identical, so that's two instances of the same class, implementing a two-dimensional array).

Jonatan Hedborg
Member #4,886
July 2004
avatar

I'm betting you are doing something wonky with the arrays... Try using simple 1D STL::vectors instead.

-------
Sweden: Free from the shackles of Democracy since 2008-06-18!

InfiniteLoop
Member #8,434
March 2007

All I am doing with the new statements is creating dynamic multidimensional arrays. If I take out the bitmap loading parts, my cleanUp code prevents any memory leaks. The problem arrizes when I throw bitmaps into the mix since you cant call delete on a variable (even though it used new) after it has had destroy_bitmap() called on it. Also, I dont wish to use vectors because I am not interested in figuring out multidimensional vectors.

Tobias Dammers
Member #2,604
August 2002
avatar

Quote:

All I am doing with the new statements is creating dynamic multidimensional arrays.

Don't.
You don't really NEED multi-dimensional arrays; in many cases, it is less confusing to just use a 1d array with enough room for everything. In fact, RAM is conceptually linear (at least since the 80836), so no array you create will be truly 2d. See also my explanations below.

Quote:

If I take out the bitmap loading parts, my cleanUp code prevents any memory leaks.

I doubt that. Plus, memory leaks are the least of your concerns right now.

Quote:

The problem arrizes when I throw bitmaps into the mix since you cant call delete on a variable (even though it used new) after it has had destroy_bitmap() called on it.

I repeat: NEVER call new or delete on BITMAPs. You can use new to allocate one or more POINTERS to BITMAPS, but not BITMAPs directly. This has nothing to do with whether or not you can call delete on a variable (of course you call it on a variable, what else?). Memory allocation for BITMAPs is done exclusively by allegro's load_bitmap(), create_bitmap() and destroy_bitmap() (and their companions).

Quote:

Also, I dont wish to use vectors because I am not interested in figuring out multidimensional vectors.

You don't have to.
Read again: Jonathan told you to use 1D-vectors; this means in order to map 2D coordinates to this 1D vector, you need to do the calculations yourself:

index_into_vector = x + vector_width * y;

Of course, you should add some range checking there.

Then; from the code you gave, I get the impression that you are using BITMAP* pointers in your game logic, which doesn't sound like a good idea to me (remember, separate logic from drawing).
A better way would be to use a grid of ints (yes, plain old ints) and use their values for special meanings (I don't know what kind of game you're making, so I'll go for something like checkers): 0 for a blank field, 1 for a white piece, 2 for a black one, and so on. In the drawing part, you iterate through the grid, and depending on its content, you choose the correct bitmap from a global bitmap list (or even better, a pre-loaded datafile), and just display that. This way, you can elegantly avoid the multiple pointer mess you have coded there, you only need an array of ints and a bitmap list.

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

Kris Asick
Member #1,424
July 2001

Just to explain to you what was happening with your initial code, InfiniteLoop:

1. ptrBitmap = new BITMAP;

  • ptrBitmap now points to a new BITMAP object.

2. ptrBitmap = create_bitmap(600, 600);

  • ptrBitmap now points to another new BITMAP object.

  • No pointer is pointing to the BITMAP created in step 1 anymore.

create_bitmap() returns a newly created pointer to a BITMAP structure, but that BITMAP structure also points to the actual contents of the bitmap you created. So, with that in mind, watch this:

1. ptrBitmap = create_bitmap(600, 600);

  • ptrBitmap now points to a new BITMAP object, which points to bitmap data stored in memory.

2. delete ptrBitmap;

  • ptrBitmap no longer points anywhere.

  • No pointer is pointing to the bitmap data created in step 1 anymore.

Aren't pointers fun? ;D

--- Kris Asick (Gemini)
--- http://www.pixelships.com

--- Kris Asick (Gemini)
--- http://www.pixelships.com

InfiniteLoop
Member #8,434
March 2007

Yeah, the original problem was already figured out. Using new in that project was an oversight on my part. It was merely a test to replicate the real problem that I am having.

So I decided to suck it up and use vectors. Problem solved. Thanks Jonatan

Go to: