Main Page | Namespace List | Class Hierarchy | Class List | Directories | File List | Namespace Members | Class Members | File Members

# KeosMemoryManager.cpp

Go to the documentation of this file.

    00001 /*
    00002  * This source file is part of KEOS (Free 3D Engine)
    00003  * For the latest info, see http://www.keosengine.org/
    00004  * E-mails : thierry.vouriot@keosengine.org, yeri@keosengine.org
    00005  *
    00006  * This program is free software; you can redistribute it and/or modify it under
    00007  * the terms of the GNU Lesser General Public License as published by the Free Software
    00008  * Foundation; either version 2 of the License, or (at your option) any later
    00009  * version.
    00010  *
    00011  * This program is distributed in the hope that it will be useful, but WITHOUT
    00012  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    00013  * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
    00014  *
    00015  * You should have received a copy of the GNU Lesser General Public License along with
    00016  * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
    00017  * Place - Suite 330, Boston, MA 02111-1307, USA, or go to
    00018  * http://www.gnu.org/copyleft/lesser.txt.
    00019  *
    00020  */
    00021
    00022 //==========================================================
    00023 // ORIGINAL COPYRIGHT FOLLOWS
    00024 //==========================================================
    00025 // Yes::Engine - Free C++ 3D engine
    00026 //
    00027 // Copyright (C) 2004-2005 Laurent Gomila
    00028 //
    00029 // This program is free software; you can redistribute it and/or
    00030 // modify it under the terms of the GNU General Public License
    00031 // as published by the Free Software Foundation; either version 2
    00032 // of the License, or (at your option) any later version.
    00033 //
    00034 // This program is distributed in the hope that it will be useful,
    00035 // but WITHOUT ANY WARRANTY; without even the implied warranty of
    00036 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    00037 // GNU General Public License for more details.
    00038 //
    00039 // You should have received a copy of the GNU General Public License
    00040 // along with this program; if not, write to the Free Software
    00041 // Foundation, Inc.,
    00042 // 59 Temple Place - Suite 330,
    00043 // Boston, MA  02111-1307, USA.
    00044 //
    00045 // E-mail : laurent.gom@gmail.com
    00046 //==========================================================
    00047
    00048 #include "KeosMemoryManager.h"
    00049 #include "KeosException.h"
    00050 #include "KeosNoMemoryMacros.h"
    00051
    00052 namespace Keos
    00053 {
    00054     //=======================================================================
    00055     // CMemoryManager implementation
    00056     //=======================================================================
    00057
    00058     //-----------------------------------------------------------------------
    00059     CMemoryManager::CMemoryManager() :
    00060     m_File(KEOS_MEMLEAKS_FILE)
    00061     {
    00062         // The file is open ?
    00063         if (!m_File)
    00064             throw CLoadingFailed(KEOS_MEMLEAKS_FILE, "Impossible to write in file", "CMemoryManager::CMemoryManager");
    00065
    00066         // Write header
    00067         m_File << "=============================================" << std::endl;
    00068         m_File << " Keos::Engine v" << KEOS_VERSION_MAJOR << "." << KEOS_VERSION_MINOR <<
    00069             "." << KEOS_VERSION_PATCH << " - Memory leak tracker - " << std::endl;
    00070         m_File << "=============================================" << std::endl << std::endl;
    00071
    00072     }
    00073
    00074     //-----------------------------------------------------------------------
    00075     CMemoryManager::~CMemoryManager()
    00076     {
    00077         if (m_Blocks.empty())
    00078         {
    00079             // Aucune fuite
    00080             m_File << std::endl;
    00081             m_File << "==================" << std::endl;
    00082             m_File << " No leak detected " << std::endl;
    00083             m_File << "==================" << std::endl;
    00084         }
    00085         else
    00086         {
    00087             // Fuites mémoires
    00088             m_File << std::endl;
    00089             m_File << "===============================" << std::endl;
    00090             m_File << " Some leaks have been detected " << std::endl;
    00091             m_File << "===============================" << std::endl;
    00092             m_File << std::endl;
    00093
    00094             ReportLeaks();
    00095         }
    00096     }
    00097
    00098     //-----------------------------------------------------------------------
    00099     CMemoryManager& CMemoryManager::Instance()
    00100     {
    00101         static CMemoryManager sInst;
    00102
    00103         return sInst;
    00104     }
    00105
    00106     //-----------------------------------------------------------------------
    00107     void CMemoryManager::ReportLeaks()
    00108     {
    00109         // Détail des fuites
    00110         size_t nTotalSize = 0;
    00111         for (TBlockMap::iterator i = m_Blocks.begin(); i != m_Blocks.end(); ++i)
    00112         {
    00113             // Ajout de la taille du bloc au cumul
    00114             nTotalSize += i->second.nSize;
    00115
    00116             // Inscription dans le fichier des informations sur le bloc courant
    00117             m_File << "-> 0x" << i->first
    00118                    << " | "   << std::setw(7) << std::setfill(' ') << static_cast<int>(i->second.nSize) << " bytes"
    00119                    << " | "   << i->second.File.Filename() << " (" << i->second.nLine << ")" << std::endl;
    00120
    00121             // Libération de la mémoire
    00122             free(i->first);
    00123         }
    00124
    00125         // Affichage du cumul des fuites
    00126         m_File << std::endl << std::endl << "-- "
    00127                << static_cast<int>(m_Blocks.size()) << " Blocks not released, "
    00128                << static_cast<int>(nTotalSize)       << " bytes --"
    00129                << std::endl;
    00130     }
    00131
    00132     //-----------------------------------------------------------------------
    00133     void* CMemoryManager::Allocate(size_t nSize, const CFile& File, int nLine, bool bArray)
    00134     {
    00135         // Allocation de la mémoire
    00136         void* pPtr = malloc(nSize);
    00137
    00138         // Ajout du bloc à la liste des blocs alloués
    00139         TBlock NewBlock;
    00140         NewBlock.nSize  = nSize;
    00141         NewBlock.File   = File;
    00142         NewBlock.nLine  = nLine;
    00143         NewBlock.bArray = bArray;
    00144         m_Blocks[pPtr]  = NewBlock;
    00145
    00146         // Loggization
    00147         m_File << "++ Allocation    | 0x" << pPtr
    00148                << " | " << std::setw(7) << std::setfill(' ') << static_cast<int>(NewBlock.nSize) << " bytes"
    00149                << " | " << NewBlock.File.Filename() << " (" << NewBlock.nLine << ")" << std::endl;
    00150
    00151         return pPtr;
    00152     }
    00153
    00154     //-----------------------------------------------------------------------
    00155     void CMemoryManager::Free(void* pPtr, bool bArray)
    00156     {
    00157         // Recherche de l'adresse dans les blocs alloués
    00158         TBlockMap::iterator It = m_Blocks.find(pPtr);
    00159
    00160         // Si le bloc n'a pas été alloué, on génère une erreur
    00161         if (It == m_Blocks.end())
    00162         {
    00163             // En fait ça arrive souvent, du fait que le delete surchargé est pris en compte même là où on n'inclue pas DebugNew.h,
    00164             // mais pas la macro pour le new
    00165             // Dans ce cas on détruit le bloc et on quitte immédiatement
    00166             free(pPtr);
    00167             return;
    00168         }
    00169
    00170         // Si le type d'allocation ne correspond pas, on génère une erreur
    00171         if (It->second.bArray != bArray)
    00172         {
    00173             throw CBadDelete(pPtr, It->second.File.Filename(), It->second.nLine, !bArray);
    00174         }
    00175
    00176         // Finalement, si tout va bien, on supprime le bloc et on loggiz tout ça
    00177         m_File << "-- Deallocation  | 0x" << pPtr
    00178                << " | " << std::setw(7) << std::setfill(' ') << static_cast<int>(It->second.nSize) << " bytes"
    00179                << " | " << m_DeleteStack.top().File.Filename() << " (" << m_DeleteStack.top().nLine << ")" << std::endl;
    00180         m_Blocks.erase(It);
    00181         m_DeleteStack.pop();
    00182
    00183         // Libération de la mémoire
    00184         free(pPtr);
    00185     }
    00186
    00187     //-----------------------------------------------------------------------
    00188     void CMemoryManager::NextDelete(const CFile& File, int nLine)
    00189     {
    00190         TBlock Delete;
    00191         Delete.File = File;
    00192         Delete.nLine = nLine;
    00193
    00194         m_DeleteStack.push(Delete);
    00195     }
    00196
    00197 } // namespace Keos