Commit b04de0ca authored by Maciej Suminski's avatar Maciej Suminski

Fixed memory leaks in containers.

parent d13355f7
...@@ -42,7 +42,7 @@ ...@@ -42,7 +42,7 @@
using namespace KiGfx; using namespace KiGfx;
CACHED_CONTAINER::CACHED_CONTAINER( unsigned int aSize ) : CACHED_CONTAINER::CACHED_CONTAINER( unsigned int aSize ) :
VERTEX_CONTAINER( aSize ) VERTEX_CONTAINER( aSize ), m_item( NULL )
{ {
// In the beginning there is only free space // In the beginning there is only free space
m_freeChunks.insert( Chunk( aSize, 0 ) ); m_freeChunks.insert( Chunk( aSize, 0 ) );
...@@ -51,35 +51,45 @@ CACHED_CONTAINER::CACHED_CONTAINER( unsigned int aSize ) : ...@@ -51,35 +51,45 @@ CACHED_CONTAINER::CACHED_CONTAINER( unsigned int aSize ) :
void CACHED_CONTAINER::SetItem( VERTEX_ITEM* aItem ) void CACHED_CONTAINER::SetItem( VERTEX_ITEM* aItem )
{ {
if( aItem == NULL ) wxASSERT( aItem != NULL );
{
wxASSERT( m_item != NULL );
// Finishing the item m_item = aItem;
if( m_itemSize < m_chunkSize ) m_itemSize = m_item->GetSize();
{ m_chunkSize = m_itemSize;
// There is some not used but reserved memory left, so we should return it to the pool
int itemOffset = m_item->GetOffset();
// Add the not used memory back to the pool if( m_itemSize == 0 )
m_freeChunks.insert( Chunk( m_chunkSize - m_itemSize, itemOffset + m_itemSize ) ); m_items.insert( m_item ); // The item was not stored before
m_freeSpace += ( m_chunkSize - m_itemSize );
// mergeFreeChunks();
}
m_item = NULL;
}
else else
m_chunkOffset = m_item->GetOffset();
#if CACHED_CONTAINER_TEST > 1
wxLogDebug( wxT( "Adding/editing item 0x%08lx (size %d)" ), (long) m_item, m_itemSize );
#endif
}
void CACHED_CONTAINER::FinishItem()
{
wxASSERT( m_item != NULL );
wxASSERT( m_item->GetSize() == m_itemSize );
// Finishing the previously edited item
if( m_itemSize < m_chunkSize )
{ {
m_item = aItem; // There is some not used but reserved memory left, so we should return it to the pool
m_itemSize = m_item->GetSize(); int itemOffset = m_item->GetOffset();
m_chunkSize = m_itemSize;
if( m_itemSize == 0 ) // Add the not used memory back to the pool
m_items.insert( m_item ); // The item was not stored before m_freeChunks.insert( Chunk( m_chunkSize - m_itemSize, itemOffset + m_itemSize ) );
else m_freeSpace += ( m_chunkSize - m_itemSize );
m_chunkOffset = m_item->GetOffset(); // mergeFreeChunks(); // veery slow and buggy
} }
#if CACHED_CONTAINER_TEST > 1
wxLogDebug( wxT( "Finishing item 0x%08lx (size %d)" ), (long) m_item, m_itemSize );
test();
m_item = NULL; // electric fence
#endif
} }
...@@ -109,6 +119,7 @@ VERTEX* CACHED_CONTAINER::Allocate( unsigned int aSize ) ...@@ -109,6 +119,7 @@ VERTEX* CACHED_CONTAINER::Allocate( unsigned int aSize )
VERTEX* reserved = &m_vertices[m_chunkOffset + m_itemSize]; VERTEX* reserved = &m_vertices[m_chunkOffset + m_itemSize];
m_itemSize += aSize; m_itemSize += aSize;
// Now the item officially possesses the memory chunk
m_item->setSize( m_itemSize ); m_item->setSize( m_itemSize );
// The content has to be updated // The content has to be updated
...@@ -117,16 +128,40 @@ VERTEX* CACHED_CONTAINER::Allocate( unsigned int aSize ) ...@@ -117,16 +128,40 @@ VERTEX* CACHED_CONTAINER::Allocate( unsigned int aSize )
#if CACHED_CONTAINER_TEST > 1 #if CACHED_CONTAINER_TEST > 1
test(); test();
#endif #endif
#if CACHED_CONTAINER_TEST > 2
showFreeChunks();
showReservedChunks();
#endif
return reserved; return reserved;
} }
void CACHED_CONTAINER::Erase() void CACHED_CONTAINER::Delete( VERTEX_ITEM* aItem )
{ {
wxASSERT( m_item != NULL ); wxASSERT( aItem != NULL );
wxASSERT( m_items.find( aItem ) != m_items.end() );
int size = aItem->GetSize();
int offset = aItem->GetOffset();
freeItem( m_item ); #if CACHED_CONTAINER_TEST > 1
wxLogDebug( wxT( "Removing 0x%08lx (size %d offset %d)" ), (long) aItem, size, offset );
#endif
// Insert a free memory chunk entry in the place where item was stored
if( size > 0 )
{
m_freeChunks.insert( Chunk( size, offset ) );
m_freeSpace += size;
// Indicate that the item is not stored in the container anymore
aItem->setSize( 0 );
}
m_items.erase( aItem );
#if CACHED_CONTAINER_TEST > 1
test();
#endif
// Dynamic memory freeing, there is no point in holding // Dynamic memory freeing, there is no point in holding
// a large amount of memory when there is no use for it // a large amount of memory when there is no use for it
...@@ -176,10 +211,10 @@ VERTEX* CACHED_CONTAINER::GetVertices( const VERTEX_ITEM* aItem ) const ...@@ -176,10 +211,10 @@ VERTEX* CACHED_CONTAINER::GetVertices( const VERTEX_ITEM* aItem ) const
unsigned int CACHED_CONTAINER::reallocate( unsigned int aSize ) unsigned int CACHED_CONTAINER::reallocate( unsigned int aSize )
{ {
wxASSERT( aSize > 0 );
#if CACHED_CONTAINER_TEST > 2 #if CACHED_CONTAINER_TEST > 2
wxLogDebug( wxT( "Resize 0x%08x to %d" ), (int) m_item, aSize ); wxLogDebug( wxT( "Resize 0x%08lx from %d to %d" ), (long) m_item, m_itemSize, aSize );
showFreeChunks();
showReservedChunks();
#endif #endif
// Is there enough space to store vertices? // Is there enough space to store vertices?
...@@ -203,7 +238,7 @@ unsigned int CACHED_CONTAINER::reallocate( unsigned int aSize ) ...@@ -203,7 +238,7 @@ unsigned int CACHED_CONTAINER::reallocate( unsigned int aSize )
return UINT_MAX; return UINT_MAX;
} }
// Look for the free space of at least given size // Look for the free space chunk of at least given size
FreeChunkMap::iterator newChunk = m_freeChunks.lower_bound( aSize ); FreeChunkMap::iterator newChunk = m_freeChunks.lower_bound( aSize );
if( newChunk == m_freeChunks.end() ) if( newChunk == m_freeChunks.end() )
...@@ -240,6 +275,7 @@ unsigned int CACHED_CONTAINER::reallocate( unsigned int aSize ) ...@@ -240,6 +275,7 @@ unsigned int CACHED_CONTAINER::reallocate( unsigned int aSize )
m_itemSize * VertexSize ); m_itemSize * VertexSize );
// Free the space previously used by the chunk // Free the space previously used by the chunk
wxASSERT( m_itemSize > 0 );
m_freeChunks.insert( Chunk( m_itemSize, m_chunkOffset ) ); m_freeChunks.insert( Chunk( m_itemSize, m_chunkOffset ) );
m_freeSpace += m_itemSize; m_freeSpace += m_itemSize;
} }
...@@ -254,15 +290,10 @@ unsigned int CACHED_CONTAINER::reallocate( unsigned int aSize ) ...@@ -254,15 +290,10 @@ unsigned int CACHED_CONTAINER::reallocate( unsigned int aSize )
} }
m_freeSpace -= aSize; m_freeSpace -= aSize;
// mergeFreeChunks(); // mergeFreeChunks(); // veery slow and buggy
m_item->setOffset( chunkOffset ); m_item->setOffset( chunkOffset );
#if CACHED_CONTAINER_TEST > 2
showFreeChunks();
showReservedChunks();
#endif
return chunkOffset; return chunkOffset;
} }
...@@ -271,11 +302,10 @@ bool CACHED_CONTAINER::defragment( VERTEX* aTarget ) ...@@ -271,11 +302,10 @@ bool CACHED_CONTAINER::defragment( VERTEX* aTarget )
{ {
#if CACHED_CONTAINER_TEST > 0 #if CACHED_CONTAINER_TEST > 0
wxLogDebug( wxT( "Defragmenting" ) ); wxLogDebug( wxT( "Defragmenting" ) );
#endif
#ifdef __WXDEBUG__
prof_counter totalTime; prof_counter totalTime;
prof_start( &totalTime, false ); prof_start( &totalTime, false );
#endif /* __WXDEBUG__ */ #endif
if( aTarget == NULL ) if( aTarget == NULL )
{ {
...@@ -313,14 +343,15 @@ bool CACHED_CONTAINER::defragment( VERTEX* aTarget ) ...@@ -313,14 +343,15 @@ bool CACHED_CONTAINER::defragment( VERTEX* aTarget )
// Now there is only one big chunk of free memory // Now there is only one big chunk of free memory
m_freeChunks.clear(); m_freeChunks.clear();
wxASSERT( m_freeSpace > 0 );
m_freeChunks.insert( Chunk( m_freeSpace, m_currentSize - m_freeSpace ) ); m_freeChunks.insert( Chunk( m_freeSpace, m_currentSize - m_freeSpace ) );
#ifdef __WXDEBUG__ #if CACHED_CONTAINER_TEST > 0
prof_end( &totalTime ); prof_end( &totalTime );
wxLogDebug( wxT( "Defragmented the container storing %d vertices / %.1f ms" ), wxLogDebug( wxT( "Defragmented the container storing %d vertices / %.1f ms" ),
m_currentSize - m_freeSpace, (double) totalTime.value / 1000.0 ); m_currentSize - m_freeSpace, (double) totalTime.value / 1000.0 );
#endif /* __WXDEBUG__ */ #endif
return true; return true;
} }
...@@ -331,10 +362,10 @@ void CACHED_CONTAINER::mergeFreeChunks() ...@@ -331,10 +362,10 @@ void CACHED_CONTAINER::mergeFreeChunks()
if( m_freeChunks.size() <= 1 ) // There are no chunks that can be merged if( m_freeChunks.size() <= 1 ) // There are no chunks that can be merged
return; return;
#ifdef __WXDEBUG__ #ifdef CACHED_CONTAINER_TEST > 0
prof_counter totalTime; prof_counter totalTime;
prof_start( &totalTime, false ); prof_start( &totalTime, false );
#endif /* __WXDEBUG__ */ #endif
// Reversed free chunks map - this one stores chunk size with its offset as the key // Reversed free chunks map - this one stores chunk size with its offset as the key
std::list<Chunk> freeChunks; std::list<Chunk> freeChunks;
...@@ -375,11 +406,11 @@ void CACHED_CONTAINER::mergeFreeChunks() ...@@ -375,11 +406,11 @@ void CACHED_CONTAINER::mergeFreeChunks()
// Add the last one // Add the last one
m_freeChunks.insert( std::make_pair( size, offset ) ); m_freeChunks.insert( std::make_pair( size, offset ) );
#ifdef __WXDEBUG__ #ifdef CACHED_CONTAINER_TEST > 0
prof_end( &totalTime ); prof_end( &totalTime );
wxLogDebug( wxT( "Merged free chunks / %.1f ms" ), (double) totalTime.value / 1000.0 ); wxLogDebug( wxT( "Merged free chunks / %.1f ms" ), (double) totalTime.value / 1000.0 );
#endif /* __WXDEBUG__ */ #endif
test(); test();
} }
...@@ -387,6 +418,8 @@ void CACHED_CONTAINER::mergeFreeChunks() ...@@ -387,6 +418,8 @@ void CACHED_CONTAINER::mergeFreeChunks()
bool CACHED_CONTAINER::resizeContainer( unsigned int aNewSize ) bool CACHED_CONTAINER::resizeContainer( unsigned int aNewSize )
{ {
wxASSERT( aNewSize != m_currentSize );
#if CACHED_CONTAINER_TEST > 0 #if CACHED_CONTAINER_TEST > 0
wxLogDebug( wxT( "Resizing container from %d to %d" ), m_currentSize, aNewSize ); wxLogDebug( wxT( "Resizing container from %d to %d" ), m_currentSize, aNewSize );
#endif #endif
...@@ -413,6 +446,7 @@ bool CACHED_CONTAINER::resizeContainer( unsigned int aNewSize ) ...@@ -413,6 +446,7 @@ bool CACHED_CONTAINER::resizeContainer( unsigned int aNewSize )
// We have to correct freeChunks after defragmentation // We have to correct freeChunks after defragmentation
m_freeChunks.clear(); m_freeChunks.clear();
wxASSERT( aNewSize - reservedSpace() > 0 );
m_freeChunks.insert( Chunk( aNewSize - reservedSpace(), reservedSpace() ) ); m_freeChunks.insert( Chunk( aNewSize - reservedSpace(), reservedSpace() ) );
} }
else else
...@@ -439,21 +473,6 @@ bool CACHED_CONTAINER::resizeContainer( unsigned int aNewSize ) ...@@ -439,21 +473,6 @@ bool CACHED_CONTAINER::resizeContainer( unsigned int aNewSize )
} }
void CACHED_CONTAINER::freeItem( VERTEX_ITEM* aItem )
{
int size = aItem->GetSize();
int offset = aItem->GetOffset();
// Insert a free memory chunk entry in the place where item was stored
m_freeChunks.insert( Chunk( size, offset ) );
m_freeSpace += size;
m_items.erase( aItem );
// Indicate that the item is not stored in the container anymore
aItem->setSize( 0 );
}
unsigned int CACHED_CONTAINER::getPowerOf2( unsigned int aNumber ) const unsigned int CACHED_CONTAINER::getPowerOf2( unsigned int aNumber ) const
{ {
unsigned int power = 1; unsigned int power = 1;
...@@ -476,6 +495,7 @@ void CACHED_CONTAINER::showFreeChunks() ...@@ -476,6 +495,7 @@ void CACHED_CONTAINER::showFreeChunks()
{ {
unsigned int offset = getChunkOffset( *it ); unsigned int offset = getChunkOffset( *it );
unsigned int size = getChunkSize( *it ); unsigned int size = getChunkSize( *it );
wxASSERT( size > 0 );
wxLogDebug( wxT( "[0x%08x-0x%08x] (size %d)" ), wxLogDebug( wxT( "[0x%08x-0x%08x] (size %d)" ),
offset, offset + size - 1, size ); offset, offset + size - 1, size );
...@@ -494,9 +514,10 @@ void CACHED_CONTAINER::showReservedChunks() ...@@ -494,9 +514,10 @@ void CACHED_CONTAINER::showReservedChunks()
VERTEX_ITEM* item = *it; VERTEX_ITEM* item = *it;
unsigned int offset = item->GetOffset(); unsigned int offset = item->GetOffset();
unsigned int size = item->GetSize(); unsigned int size = item->GetSize();
wxASSERT( size > 0 );
wxLogDebug( wxT( "[0x%08x-0x%08x] @ 0x%08x (size %d)" ), wxLogDebug( wxT( "[0x%08x-0x%08x] @ 0x%08lx (size %d)" ),
offset, offset + size - 1, (int) item, size ); offset, offset + size - 1, (long) item, size );
} }
} }
......
...@@ -82,11 +82,6 @@ VERTEX* NONCACHED_CONTAINER::Allocate( unsigned int aSize ) ...@@ -82,11 +82,6 @@ VERTEX* NONCACHED_CONTAINER::Allocate( unsigned int aSize )
} }
void NONCACHED_CONTAINER::Erase()
{
}
void NONCACHED_CONTAINER::Clear() void NONCACHED_CONTAINER::Clear()
{ {
m_freePtr = 0; m_freePtr = 0;
......
...@@ -638,6 +638,7 @@ int OPENGL_GAL::BeginGroup() ...@@ -638,6 +638,7 @@ int OPENGL_GAL::BeginGroup()
void OPENGL_GAL::EndGroup() void OPENGL_GAL::EndGroup()
{ {
cachedManager.FinishItem();
isGrouping = false; isGrouping = false;
} }
...@@ -662,6 +663,7 @@ void OPENGL_GAL::ChangeGroupDepth( int aGroupNumber, int aDepth ) ...@@ -662,6 +663,7 @@ void OPENGL_GAL::ChangeGroupDepth( int aGroupNumber, int aDepth )
void OPENGL_GAL::DeleteGroup( int aGroupNumber ) void OPENGL_GAL::DeleteGroup( int aGroupNumber )
{ {
// Frees memory in the container as well
groups.erase( aGroupNumber ); groups.erase( aGroupNumber );
} }
......
...@@ -88,10 +88,15 @@ void VERTEX_MANAGER::SetItem( VERTEX_ITEM& aItem ) const ...@@ -88,10 +88,15 @@ void VERTEX_MANAGER::SetItem( VERTEX_ITEM& aItem ) const
} }
void VERTEX_MANAGER::FinishItem() const
{
m_container->FinishItem();
}
void VERTEX_MANAGER::FreeItem( VERTEX_ITEM& aItem ) const void VERTEX_MANAGER::FreeItem( VERTEX_ITEM& aItem ) const
{ {
m_container->SetItem( &aItem ); m_container->Delete( &aItem );
m_container->Erase();
} }
......
...@@ -137,9 +137,3 @@ void VIEW_ITEM::deleteGroups() ...@@ -137,9 +137,3 @@ void VIEW_ITEM::deleteGroups()
m_groups = NULL; m_groups = NULL;
m_groupsSize = 0; m_groupsSize = 0;
} }
bool VIEW_ITEM::storesGroups() const
{
return ( m_groupsSize > 0 );
}
...@@ -36,10 +36,8 @@ ...@@ -36,10 +36,8 @@
#include <map> #include <map>
#include <set> #include <set>
#ifdef __WXDEBUG__
// Debug messages verbosity level // Debug messages verbosity level
// #define CACHED_CONTAINER_TEST 2 //#define CACHED_CONTAINER_TEST 1
#endif
namespace KiGfx namespace KiGfx
{ {
...@@ -54,11 +52,14 @@ public: ...@@ -54,11 +52,14 @@ public:
///< @copydoc VERTEX_CONTAINER::SetItem() ///< @copydoc VERTEX_CONTAINER::SetItem()
virtual void SetItem( VERTEX_ITEM* aItem ); virtual void SetItem( VERTEX_ITEM* aItem );
///< @copydoc VERTEX_CONTAINER::FinishItem()
virtual void FinishItem();
///< @copydoc VERTEX_CONTAINER::Allocate() ///< @copydoc VERTEX_CONTAINER::Allocate()
virtual VERTEX* Allocate( unsigned int aSize ); virtual VERTEX* Allocate( unsigned int aSize );
///< @copydoc VERTEX_CONTAINER::Erase() ///< @copydoc VERTEX_CONTAINER::Delete()
virtual void Erase(); virtual void Delete( VERTEX_ITEM* aItem );
///< @copydoc VERTEX_CONTAINER::Clear() ///< @copydoc VERTEX_CONTAINER::Clear()
virtual void Clear(); virtual void Clear();
...@@ -130,14 +131,6 @@ protected: ...@@ -130,14 +131,6 @@ protected:
*/ */
virtual bool resizeContainer( unsigned int aNewSize ); virtual bool resizeContainer( unsigned int aNewSize );
/**
* Function freeItem()
* frees the space occupied by the item and returns it to the free space pool.
*
* @param aItem is the item to be freed.
*/
virtual void freeItem( VERTEX_ITEM* aItem );
/** /**
* Function getPowerOf2() * Function getPowerOf2()
* returns the nearest power of 2, bigger than aNumber. * returns the nearest power of 2, bigger than aNumber.
...@@ -170,7 +163,7 @@ private: ...@@ -170,7 +163,7 @@ private:
} }
/// Debug & test functions /// Debug & test functions
#ifdef CACHED_CONTAINER_TEST #if CACHED_CONTAINER_TEST > 0
void showFreeChunks(); void showFreeChunks();
void showReservedChunks(); void showReservedChunks();
void test(); void test();
......
...@@ -50,8 +50,8 @@ public: ...@@ -50,8 +50,8 @@ public:
///< @copydoc VERTEX_CONTAINER::Allocate() ///< @copydoc VERTEX_CONTAINER::Allocate()
virtual VERTEX* Allocate( unsigned int aSize ); virtual VERTEX* Allocate( unsigned int aSize );
///< @copydoc VERTEX_CONTAINER::Erase() ///< @copydoc VERTEX_CONTAINER::Delete()
virtual void Erase(); void Delete( VERTEX_ITEM* aItem ) {};
///< @copydoc VERTEX_CONTAINER::Clear() ///< @copydoc VERTEX_CONTAINER::Clear()
virtual void Clear(); virtual void Clear();
......
...@@ -54,6 +54,12 @@ public: ...@@ -54,6 +54,12 @@ public:
*/ */
virtual void SetItem( VERTEX_ITEM* aItem ) = 0; virtual void SetItem( VERTEX_ITEM* aItem ) = 0;
/**
* Function FinishItem()
* does the cleaning after adding an item.
*/
virtual void FinishItem() {};
/** /**
* Function Allocate() * Function Allocate()
* returns allocated space (possibly resizing the reserved memory chunk or allocating a new * returns allocated space (possibly resizing the reserved memory chunk or allocating a new
...@@ -66,10 +72,12 @@ public: ...@@ -66,10 +72,12 @@ public:
virtual VERTEX* Allocate( unsigned int aSize ) = 0; virtual VERTEX* Allocate( unsigned int aSize ) = 0;
/** /**
* Function Erase() * Function Delete()
* erases all vertices associated with the current item (set by SetItem()). * erases the selected item.
*
* @param aItem is the item to be erased.
*/ */
virtual void Erase() = 0; virtual void Delete( VERTEX_ITEM* aItem ) = 0;
/** /**
* Function Clear() * Function Clear()
......
...@@ -232,6 +232,12 @@ public: ...@@ -232,6 +232,12 @@ public:
*/ */
void SetItem( VERTEX_ITEM& aItem ) const; void SetItem( VERTEX_ITEM& aItem ) const;
/**
* Function FinishItem()
* does the cleaning after adding an item.
*/
void FinishItem() const;
/** /**
* Function FreeItem() * Function FreeItem()
* frees the memory occupied by the item, so it is no longer stored in the container. * frees the memory occupied by the item, so it is no longer stored in the container.
......
...@@ -70,8 +70,7 @@ public: ...@@ -70,8 +70,7 @@ public:
ALL = 0xff ALL = 0xff
}; };
VIEW_ITEM() : m_view( NULL ), m_visible( true ), m_groups( NULL ), VIEW_ITEM() : m_view( NULL ), m_visible( true ), m_groups( NULL ), m_groupsSize( 0 ) {}
m_groupsSize( 0 ) {}
/** /**
* Destructor. For dynamic views, removes the item from the view. * Destructor. For dynamic views, removes the item from the view.
...@@ -236,7 +235,10 @@ protected: ...@@ -236,7 +235,10 @@ protected:
* *
* @returns true in case it is cached at least for one layer. * @returns true in case it is cached at least for one layer.
*/ */
virtual bool storesGroups() const; inline virtual bool storesGroups() const
{
return ( m_groupsSize > 0 );
}
/// Stores layer numbers used by the item. /// Stores layer numbers used by the item.
std::bitset<VIEW::VIEW_MAX_LAYERS> m_layers; std::bitset<VIEW::VIEW_MAX_LAYERS> m_layers;
...@@ -253,7 +255,7 @@ protected: ...@@ -253,7 +255,7 @@ protected:
m_layers.reset(); m_layers.reset();
for( int i = 0; i < aCount; ++i ) for( int i = 0; i < aCount; ++i )
m_layers.set(aLayers[i]); m_layers.set( aLayers[i] );
} }
}; };
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment