blob: 2a3529de66b874bc75023f0ea28f634cc6b1811f [file] [log] [blame]
/*
* 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";
using xercesc::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