| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| #include "XalanDiagnosticMemoryManager.hpp" |
| |
| |
| |
| #if !defined(XALAN_CLASSIC_IOSTREAMS) |
| #include <iostream> |
| #endif |
| |
| |
| |
| #include <ctype.h> |
| |
| |
| |
| #include "xercesc/util/PlatformUtils.hpp" |
| |
| |
| |
| XALAN_CPP_NAMESPACE_BEGIN |
| |
| |
| |
| XalanDiagnosticMemoryManager::XalanDiagnosticMemoryManager( |
| MemoryManager& theMemoryManager, |
| bool fAssertErrors, |
| StreamType* theStream) : |
| m_memoryManager(theMemoryManager), |
| m_assertErrors(fAssertErrors), |
| m_locked(false), |
| m_sequence(0), |
| m_highWaterMark(0), |
| m_currentAllocated(0), |
| m_allocations(theMemoryManager), |
| m_stream(theStream) |
| { |
| } |
| |
| |
| |
| XalanDiagnosticMemoryManager::~XalanDiagnosticMemoryManager() |
| { |
| if (m_allocations.size() > 0 && m_stream != 0) |
| { |
| *m_stream << "Detected memory leaks. " |
| << m_allocations.size() |
| << " blocks are still allocated.\n"; |
| } |
| } |
| |
| |
| |
| void* |
| XalanDiagnosticMemoryManager::allocate(size_type size) |
| { |
| void* theResult = 0; |
| |
| if (m_locked == true) |
| { |
| if (m_stream != 0) |
| { |
| *m_stream << "Attempt to allocate " |
| << size |
| << " bytes from locked instance " |
| << this |
| << ".\n"; |
| } |
| |
| throw LockException(); |
| } |
| else |
| { |
| theResult = |
| m_memoryManager.allocate(size); |
| assert(theResult != 0); |
| |
| assert(m_allocations.find(theResult) == m_allocations.end()); |
| |
| m_currentAllocated += size; |
| |
| if (m_currentAllocated > m_highWaterMark) |
| { |
| m_highWaterMark = m_currentAllocated; |
| } |
| |
| m_allocations.insert(MapType::value_type(theResult, Data(size, m_sequence++))); |
| } |
| |
| return theResult; |
| } |
| |
| |
| |
| void |
| XalanDiagnosticMemoryManager::deallocate(void* pointer) |
| { |
| if (m_locked == true) |
| { |
| if (m_stream != 0) |
| { |
| *m_stream << "Attempt to deallocate address " |
| << pointer |
| << " with locked instance " |
| << this |
| << ".\n"; |
| } |
| |
| throw LockException(); |
| } |
| else |
| { |
| if (pointer != 0) |
| { |
| MapType::iterator i = |
| m_allocations.find(pointer); |
| |
| if (i != m_allocations.end()) |
| { |
| m_memoryManager.deallocate(pointer); |
| |
| assert(m_currentAllocated >= i->second.m_size); |
| |
| m_currentAllocated -= i->second.m_size; |
| |
| m_allocations.erase(i); |
| } |
| else |
| { |
| if (m_stream != 0) |
| { |
| *m_stream << "Attempt to free unallocated address " |
| << pointer |
| << " with instance " |
| << this |
| << ".\n"; |
| } |
| |
| assert(!m_assertErrors); |
| } |
| } |
| } |
| } |
| |
| |
| |
| MemoryManager* |
| XalanDiagnosticMemoryManager::getExceptionMemoryManager() |
| { |
| return &m_memoryManager; |
| } |
| |
| |
| |
| void |
| XalanDiagnosticMemoryManager::dumpStatistics( |
| StreamType* theStream, |
| size_type theBytesToDump) |
| { |
| StreamType* const diagStream = theStream != 0 ? theStream : m_stream; |
| |
| if (diagStream != 0) |
| { |
| *diagStream << "Total number of allocations: " |
| << m_sequence |
| << ".\n" |
| << "Total current allocations: " |
| << m_allocations.size() |
| << ".\n" |
| << "Total bytes currently allocated: " |
| << m_currentAllocated |
| << ".\n" |
| << "Peak bytes allocated: " |
| << m_highWaterMark |
| << ".\n"; |
| |
| for (const_iterator i = m_allocations.begin(); |
| i != m_allocations.end(); |
| ++i) |
| { |
| const void* const thePointer = i->first; |
| const Data& theData = i->second; |
| |
| XALAN_USING_STD(dec); |
| |
| *diagStream << "Block at address " |
| << thePointer |
| << " with sequence " |
| << dec |
| << theData.m_sequence |
| << " is " |
| << theData.m_size |
| << " bytes long.\n"; |
| |
| XALAN_USING_XERCES(XMLPlatformUtils); |
| |
| const size_type theHeaderSize = |
| XMLPlatformUtils::alignPointerForNewBlockAllocation(sizeof(MemoryManager*)); |
| |
| const char* const theChars = |
| reinterpret_cast<const char*>(thePointer) + |
| theHeaderSize; |
| |
| const unsigned char* const theUChars = |
| reinterpret_cast<const unsigned char*>(theChars); |
| |
| if (theBytesToDump != 0) |
| { |
| XALAN_USING_STD(hex); |
| |
| const size_type theCount = |
| theBytesToDump > theData.m_size ? |
| theData.m_size : |
| theBytesToDump; |
| |
| { |
| *diagStream << "("; |
| |
| for (size_type j = 0; j < theCount; ++j) |
| { |
| const char ch = isprint(theChars[j]) ? |
| theChars[j] : |
| ' '; |
| |
| *diagStream << ch; |
| } |
| |
| *diagStream << ") "; |
| } |
| |
| if (theCount < theBytesToDump) |
| { |
| for (size_type j = theCount; j < theBytesToDump; ++j) |
| { |
| *diagStream << ' '; |
| } |
| } |
| |
| { |
| *diagStream << hex; |
| |
| for (size_type j = 0; j < theCount; ++j) |
| { |
| *diagStream << static_cast<unsigned int>(theUChars[j]) |
| << " "; |
| } |
| } |
| |
| *diagStream << "\n"; |
| } |
| } |
| } |
| } |
| |
| |
| |
| XALAN_CPP_NAMESPACE_END |