From: "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de>
Subject: Re: Memory management in games
Date: Sun, 28 Nov 2004 11:41:21 +0100
Date: 2004-11-28T11:41:21+01:00 [thread overview]
Message-ID: <1jajewg6d797p.109aqk84pt5cy$.dlg@40tude.net> (raw)
In-Reply-To: pan.2004.11.27.19.48.48.118963@n_o_p_o_r_k_a_n_d_h_a_m.abyss2.demon.co.uk
On Sat, 27 Nov 2004 19:48:48 +0000, Luke A. Guest wrote:
> Further to my posts in the game dev thread, I've decided to go back on my
> original thoughts and do the game engine in Ada (I can always *cough* port
> *cough* gnat *cough* ;-D).
>
> Now, one of my design requirements is that I *must* be able to see *all*
> memory allocations and track them, this is so I can build in debugging
> tools into my engine. I have just done this in C++ by overriding the
> global new/delete operators and using macros to redefine
> new/delete/mallo/free/calloc/etc. to point to my new memory management
> class. These macros also pass the filename and line number from where the
> memory was allocated. Also, this class keeps track of all allocations in a
> list template. I currently just dump out the contents of the list on exit.
>
> So, I need to be able to do the same in Ada. Enter Storage Pools, ok, it's
> not difficult to write a pool class, I've just written a simple one. But,
> what a game engine requires is the ability to allocate a big block of
> memory and then allocate other blocks from this, so it's like a
> hierarchical pool system.
Where is any problem? Secondary pools can be allocated in the first order
pool.
> e.g. Under Linux, I might allocated a block of memory to use for the
> entire game (from a start up script), say 50Mb and this will be used for
> this session
>
> e.g On a PS2 we have something more challenging, the underlying OS needs
> some memory to load the game ELF and have some memory to use for it's own
> data structures, so in the game I say, give me 25Mb for this session.
>
> Then from this pool, other pools/objects are allocated. So, I need a way
> to override the default memory allocation method for everything, including
> library routines. Can this be done portably?
I depends on what libraries you mean. Normally a well-designed library does
not privately allocate anything large. So you can estimate the upper bound
of heap memory required for it and then limit the heap (= the pool you
cannot control) at linkage.
And, well, I would say that you should better care about stack if you have
memory constraints.
> I know I can specify the
> T'Storage_Pool for a type, will this work for libgnat.a types as well?
No, it is C++ mindset. In Ada pool is associated not with the type of
objects, but with the type of pointers to objects. I.e. you can have
objects of the same type T allocated in different pools. It is more
flexible. (but also more restrictive if you want to break something written
by other people (:-))
> I've seen that GNAT provides the System.Memory package, this isn't
> standard, so should I just go out of my way and import the memory
> allocation functions I require (malloc on Linux, memalign on PS2, etc.)?
Theoretically you could implement your own pool on the top of the standard
pool or malloc/free, just by routing Allocate / Deallocate there. But it is
cleaner to implement it new, on a chunk of raw memory. Especially if you
need some additional memory tracking / debugging. There are numerous
algorithms and methods. As always, Knuth is a good starting point.
> Also, what would be the best method of passing the function name where the
> allocation call is, through to the allocator, so that I can show where an
> allocation was made?
If you use GNAT then (only for debugging, may not work on some targets!)
with Ada.Text_IO; use Ada.Text_IO;
with GNAT.Traceback; use GNAT.Traceback;
with GNAT.Traceback.Symbolic; use GNAT.Traceback.Symbolic;
procedure Call_Stack is
TB : Tracebacks_Array (1..100);
Len : Natural;
begin
Call_Chain (TB, Len);
Put_Line (Symbolic_Traceback (TB (1..Len)));
end Call_Stack;
This would print the call stack at any point of the program you call to
Call_Stack. Of course you can modify it to store the call chain instead of
printing.
BUT, look, I have an impression that you are paying too much attention to
memory leaks. But Ada is not C++! (:-))
Further to this point, for a game engine I would not use dynamic allocation
too much. Perhaps I would not use it at all, maybe except for a pair or so
user-defined stack pools. For truly dynamic objects like characters etc, I
would use a reference counting garbage collection (an example and a stack
pool implementation can be found ion my page
http://www.dmitry-kazakov.de/ada/components.htm).
> I could use gnatprep I suppose, but obviously would
> prefer to be portable. FYI, there will be two builds as memory allocation
> tracking would not be in the final release mode build as it's extra
> overhead.
Ah, but then you should not care about portability. Debug it with GNAT
only, release it with everything else.
--
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de
prev parent reply other threads:[~2004-11-28 10:41 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2004-11-27 19:48 Memory management in games Luke A. Guest
2004-11-28 0:53 ` David Botton
2004-11-28 1:43 ` Luke A. Guest
2004-11-28 10:41 ` Dmitry A. Kazakov [this message]
replies disabled
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox