source: GTP/trunk/App/Demos/Geom/OgreStuff/include/OgreMemoryManager.h @ 1812

Revision 1812, 17.0 KB checked in by gumbau, 18 years ago (diff)
RevLine 
[1812]1/*
2-----------------------------------------------------------------------------
3This source file is part of OGRE
4(Object-oriented Graphics Rendering Engine)
5For the latest info, see http://www.ogre3d.org/
6
7Copyright (c) 2000-2005 The OGRE Team
8Also see acknowledgements in Readme.html
9
10This program is free software; you can redistribute it and/or modify it under
11the terms of the GNU Lesser General Public License as published by the Free Software
12Foundation; either version 2 of the License, or (at your option) any later
13version.
14
15This program is distributed in the hope that it will be useful, but WITHOUT
16ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
18
19You should have received a copy of the GNU Lesser General Public License along with
20this program; if not, write to the Free Software Foundation, Inc., 59 Temple
21Place - Suite 330, Boston, MA 02111-1307, USA, or go to
22http://www.gnu.org/copyleft/lesser.txt.
23-----------------------------------------------------------------------------
24*/
25//---- ORIGINAL COPYRIGHT FOLLOWS -------------------------------------------
26// ---------------------------------------------------------------------------------------------------------------------------------
27// Copyright 2000, Paul Nettle. All rights reserved.
28//
29// You are free to use this source code in any commercial or non-commercial product.
30//
31// mmgr.cpp - Memory manager & tracking software
32//
33// The most recent version of this software can be found at: ftp://ftp.GraphicsPapers.com/pub/ProgrammingTools/MemoryManagers/
34//
35// [NOTE: Best when viewed with 8-character tabs]
36//
37// ---------------------------------------------------------------------------------------------------------------------------------
38#ifndef __MemoryManager_H__
39#define __MemoryManager_H__
40
41#include "OgrePlatform.h"
42#include "OgreStdHeaders.h"
43
44namespace Ogre {
45
46    /** @page memory_manager The memory manager information page
47       
48                @subsection desc Description
49                        The memory manager is a class that handles memory (de)allocation requests.
50        @par
51            This class works like a wrapper between the actual C memory allocation
52            functions (*alloc, free) and the memory (de)allocation requests of the
53            application.
54        @par
55            Why would such a class be needed? First of all, because we had some
56            major issues with memory getting misued (read: deleted) over DLL
57            boundaries. One thing this memory manager does is solve the problem by
58            allocating all the memory in the OgreMain.dll/so process.
59        @par
60            Another use would be leak detection and memory misuse detection. With
61            a custom memory manager, calls to new/delete and *alloc/free could be
62            overseed and logged.
63        @par
64            Yet another use is the optimization of memory allocation for certain
65            object types. One of the most common examples is a small object
66            allocator.
67                @subsection types Manager types
68                        There actually are two classes, one is the standard memory manager
69                        which only addresses memory allocation problems when deallocating
70                        across processes.
71                @par
72                        The other is a modified version of the debugging memory manager written
73                        by Paul 'MidNight' Nettle (aka. the Fluid Studios Memory Manager).
74                        Obviously, the second one should be used only when debugging your
75                        application as it adds some visible overhead.
76                @par
77                        You can switch between the two memory managers by setting the value of
78                        the OGRE_DEBUG_MEMORY_MANAGER macro in OgreConfig.h
79        @subsection notes Implementation Note
80            The class contains a static member of type MemoryManager. That is
81            because we want the memory manager to be created even before we
82            override the new([])/delete([]) operators.
83                @subsection see See also
84                        <a href="http://www.flipcode.com/cgi-bin/msg.cgi?showThread=12September2000-PresentingAMemoryManager&forum=askmid&id=-1">Paul Nettle's Memory Manager page at flipCode</a> - you can get the original source form here.
85    */
86
87#if OGRE_DEBUG_MEMORY_MANAGER && OGRE_DEBUG_MODE
88
89#ifndef __FUNCTION__
90#define __FUNCTION__ "???"
91#endif
92
93}
94
95//-----------------------------------------------------------------------------
96// We have to declare the global new([])/delete([]) operators before declaring
97// the Ogre::MemoryManager class since it lists them as friend functions
98void *operator new(size_t reportedSize);
99void *operator new[](size_t reportedSize);
100void operator delete(void *reportedAddress);
101void operator delete[](void *reportedAddress);
102//-----------------------------------------------------------------------------
103
104namespace Ogre {
105
106    /** For internal use only.
107        \internal.
108        @remarks
109            This structure holds the allocation tracking information. So,
110            for each allocation made, the overhead this memory manager adds
111            is the size of this structure, the lengths of the names of the
112            file and function in which the allocation was made and the
113            padding size (which can be adjusted).
114    */
115    typedef struct tag_au
116    {
117        size_t actualSize;
118        size_t reportedSize;
119
120        void *actualAddress;
121        void *reportedAddress;
122
123        char sourceFile[40];
124        char sourceFunc[40];
125
126        unsigned int sourceLine;
127        unsigned int allocationType;
128
129        bool breakOnDealloc;
130        bool breakOnRealloc;
131
132        unsigned int allocationNumber;
133        unsigned int processID;
134
135        struct tag_au *next;
136        struct tag_au *prev;
137    } sAllocUnit;
138
139    typedef struct
140    {
141        size_t totalReportedMemory;
142        size_t totalActualMemory;
143
144        size_t peakReportedMemory;
145        size_t peakActualMemory;
146
147        size_t accumulatedReportedMemory;
148        size_t accumulatedActualMemory;
149        size_t accumulatedAllocUnitCount;
150
151        size_t totalAllocUnitCount;
152        size_t peakAllocUnitCount;
153    } sMStats;
154   
155    enum
156    {
157        m_alloc_unknown        = 0,
158        m_alloc_new            = 1,
159        m_alloc_new_array      = 2,
160        m_alloc_malloc         = 3,
161        m_alloc_calloc         = 4,
162        m_alloc_realloc        = 5,
163        m_alloc_delete         = 6,
164        m_alloc_delete_array   = 7,
165        m_alloc_free           = 8
166    };
167
168        /** See the \ref memory_manager.
169        */
170    class _OgreExport MemoryManager
171    {
172        friend void * ::operator new(size_t);
173        friend void * ::operator new[](size_t);
174        friend void ::operator delete(void*);
175        friend void ::operator delete[](void*);
176
177    public:
178        static MemoryManager& instance(void);
179
180    private:
181        /// This is used in the process tracking part of the memory manager.
182        unsigned m_uProcessIDs;
183        /// This is set to true when deinitialization takes place.
184        bool m_bDeinitTime;
185
186#ifndef __BORLANDC__
187    private:
188#else
189    public:
190#endif
191        //-------------------------------------------------------------------------
192        // Wrappers for the new/delete functions       
193        void *op_new_sc( size_t reportedSize, unsigned processID );
194        void *op_new_vc( size_t reportedSize, unsigned processID );
195
196        void *op_new_sc( size_t reportedSize, const char *sourceFile, int sourceLine, unsigned processID );
197        void *op_new_vc( size_t reportedSize, const char *sourceFile, int sourceLine, unsigned processID );
198
199        void op_del_sc( void *reportedAddress, unsigned processID );
200        void op_del_vc( void *reportedAddress, unsigned processID );
201        //-------------------------------------------------------------------------
202
203        /** This function is intended for internal use only.
204            \internal
205            @remarks
206                This function is used to return an unique handle for each process
207                calling it. The returned unsigned int is then passed to the memory
208                manager every time a re/de/allocation request is made, in order
209                to check that deallocations don't occur in processes other than the
210                ones in which allcations were made and so on.
211            @par
212                Actually, the problem of re/de/allocating in other processes was
213                solved with the addition of the new memory manager, but you may
214                want to limit the occurence of such events anyway, and this function
215                helps you do just that.
216        */
217        unsigned _getProcessID();
218
219    public:
220        MemoryManager();
221        ~MemoryManager();
222
223        //-------------------------------------------------------------------------
224        // Used by the macros     
225        void setOwner(const char *file, const unsigned int line, const char *func);
226        //-------------------------------------------------------------------------
227
228        //-------------------------------------------------------------------------
229        // Allocation breakpoints       
230        bool &breakOnRealloc(void *reportedAddress);
231        bool &breakOnDealloc( void *reportedAddress );
232        void breakOnAlloc( unsigned int count );
233        //-------------------------------------------------------------------------
234
235        //-------------------------------------------------------------------------
236        // The meat & potatoes of the memory tracking software
237
238        /** This function is intended for internal use only.
239            \internal
240            @remarks
241                This function is the actual memory allocator and acts as a bridge
242                between OGRE and the C/C++ alloc/calloc functions.
243            @par
244                While memory allocation requests are made trough this function,
245                the tracking of memory addresses is possible. Therefore, attempting
246                to deallocate a portion of memory that was not allocated using
247                this function will result in a warning given by the deallocator,
248                dllocMem.
249        */
250        void * allocMem(
251            const char *sourceFile,
252            const unsigned int sourceLine,
253            const char *sourceFunc,
254            const unsigned int allocationType,
255            const size_t reportedSize,
256            const unsigned processID );
257
258        /** This function is intended for internal use only.
259            \internal
260            @remarks
261                This function is the actual memory reallocator and acts as a bridge
262                between OGRE and the C/C++ realloc function.
263            @par
264                While memory reallocation requests are made trough this function,
265                the tracking of memory addresses is possible. Therefore, attempting
266                to deallocate a portion of memory that was not reallocated using
267                this function will result in a warning given by the deallocator,
268                dllocMem.
269            @par
270                As well, trying to reallocate memory that was not allocated using
271                mallc/calloc will result in a warning.
272        */
273        void * rllocMem(
274            const char *sourceFile,
275            const unsigned int sourceLine,
276            const char *sourceFunc,
277            const unsigned int reallocationType,
278            const size_t reportedSize,
279            void *reportedAddress,
280            const unsigned processID );
281
282        /** This function is intended for internal use only.
283            \internal
284            @remarks
285                This function is the actual memory deallocator and acts as a
286                bridge between OGRE and the C/C++ free function.
287            @par
288                While memory deallocation requests are made trough this function,
289                the tracking of memory addresses is possible. Therefore, attempting
290                to deallocate a portion of memory that was not allocated using
291                allocMem or rllocMem, trying to deallocate memory that was
292                allocated with malloc using delete (and the corresponding
293                permutations) or trying to deallocate memory allocated from from
294                process will result in a warning.
295            @note
296                Actually, memory can be allocated in one process and deallocated
297                in another, since the actual (de)allocation takes place in the
298                memory space of the OgreMain library.
299            @par
300                Tracking this kind of (possible) errors exists because users may
301                want to write their own memory allocator later on or they'd like
302                to get rid of OGRE's memory allocator.
303        */
304        void dllocMem(
305            const char *sourceFile,
306            const unsigned int sourceLine,
307            const char *sourceFunc,
308            const unsigned int deallocationType,
309            const void *reportedAddress,
310            const unsigned processID );
311        //-------------------------------------------------------------------------
312
313        //-------------------------------------------------------------------------
314        // Utilitarian functions       
315        bool validateAddr(const void *reportedAddress);
316        bool validateAlloc(const sAllocUnit *allocUnit);
317        bool validateAllAllocs();
318        //-------------------------------------------------------------------------
319
320        //-------------------------------------------------------------------------
321        // Unused RAM calculations       
322        unsigned int calcUnused( const sAllocUnit *allocUnit );
323        unsigned int calcAllUnused();
324        //-------------------------------------------------------------------------
325
326        //-------------------------------------------------------------------------
327        // Logging and reporting       
328        void dumpAllocUnit( const sAllocUnit *allocUnit, const char *prefix = "" );
329        void dumpMemReport( const char *filename = "memreport.log", const bool overwrite = true );
330        sMStats getMemStats();           
331        //-------------------------------------------------------------------------       
332    };
333}
334
335/** This variable exists separately in each module that links to the OGRE library
336    and is used to track the ID of the current process from the perspective
337    of the memory manager.
338    @see
339        unsigned Ogre::MemoryManager::_getProcessID()
340*/
341static unsigned gProcessID = 0;
342
343// When compiling in Visual C++ (occuring in VS2005 Express but not for VC 7.1) with
344// managed C++, should put the new([])/delete([]) overrides inside unmanaged context,
345// otherwise Visual C++ will link with overridden version of new([]) and CRT version
346// of delete([]), thus, mess up both of OGRE memory manager and CRT memory manager.
347#if defined(__cplusplus_cli)
348#pragma managed(push, off)
349#endif
350//-----------------------------------------------------------------------------
351// Overridden global new([])/delete([]) functions
352//
353inline void *operator new(size_t reportedSize)
354{
355    if( !gProcessID )
356        gProcessID = Ogre::MemoryManager::instance()._getProcessID();
357    return Ogre::MemoryManager::instance().op_new_sc( reportedSize, gProcessID );
358}
359inline void *operator new[](size_t reportedSize)
360{
361    if( !gProcessID )
362        gProcessID = Ogre::MemoryManager::instance()._getProcessID();
363    return Ogre::MemoryManager::instance().op_new_vc( reportedSize, gProcessID );
364}
365
366inline void operator delete(void *reportedAddress)
367{
368    Ogre::MemoryManager::instance().op_del_sc( reportedAddress, gProcessID );   
369}
370inline void operator delete[](void *reportedAddress)
371{
372    Ogre::MemoryManager::instance().op_del_vc( reportedAddress, gProcessID );
373}
374//-----------------------------------------------------------------------------
375#if defined(__cplusplus_cli)
376#pragma managed(pop)
377#endif
378
379//-----------------------------------------------------------------------------
380// This header adds the *alloc/free macros, wrapping the C functions
381#include "OgreMemoryMacros.h"
382//-----------------------------------------------------------------------------
383
384#else
385
386        /** See the \ref memory_manager.
387        */
388    class _OgreExport MemoryManager
389    {
390    public:
391        static MemoryManager& instance(void);
392
393        MemoryManager();
394        ~MemoryManager();
395
396        /** Memory allocator - uses plain old malloc.
397        */
398        void *allocMem( const char *szFile, size_t uLine, size_t count ) throw ( );
399
400        /** Memory re-allocator - uses plain old realloc.
401        */
402        void *rllocMem( const char *szFile, size_t uLine, void *ptr , size_t count ) throw ( );
403
404        /** Memory allocator - uses plain old calloc.
405        */
406        void *cllocMem( const char *szFile, size_t uLine, size_t num, size_t size ) throw ( );
407
408        /** Memory de-allocator - uses plain old free.
409        */
410        void dllocMem( const char *szFile, size_t uLine, void *ptr ) throw ( );
411    };
412
413}
414
415#endif
416
417#endif
418
Note: See TracBrowser for help on using the repository browser.