Hi, i'm attaching a patch that adds textpage into the memory management game. I think it's mostly ok except for the missing comments and that i only cared about the pdf generator.
The only problem is that our number of memory used does not match reality as there's the administrative bytes each new/malloc needs, so our number is always smaller than the reality. Comments on the patch? For the administrative blocks thing do for (int i = 0; i <= 1000000; ++i) new double(); while(1) {} and run it though valgrind --tool=massif and see how ms_print reports the same extra-heap(lost) and useful-heap. Albert
Index: core/textpage.h =================================================================== --- core/textpage.h (revision 801658) +++ core/textpage.h (working copy) @@ -145,6 +145,8 @@ */ RegularAreaRect *textArea( TextSelection *selection ) const; + qulonglong aproxBytes() const; + private: TextPagePrivate* const d; Index: core/generator.h =================================================================== --- core/generator.h (revision 801658) +++ core/generator.h (working copy) @@ -388,6 +388,11 @@ void signalPixmapRequestDone( PixmapRequest * request ); /** + * This method must be called when a text generation has been finished. + */ + void signalTextGenerationDone( Page *page, TextPage *textPage ); + + /** * This method is called when the document is closed and not used * any longer. * Index: core/document_p.h =================================================================== --- core/document_p.h (revision 801658) +++ core/document_p.h (working copy) @@ -30,7 +30,7 @@ class QTimer; class KTemporaryFile; -struct AllocatedPixmap; +struct AllocatedData; struct RunningSearch; namespace Okular { @@ -69,7 +69,7 @@ m_lastSearchID( -1 ), m_tempFile( 0 ), m_docSize( -1 ), - m_allocatedPixmapsTotalMemory( 0 ), + m_allocatedDataTotalMemory( 0 ), m_warnedOutOfMemory( false ), m_rotation( Rotation0 ), m_exportCached( false ), @@ -122,6 +122,7 @@ * the pixmap generation @p request. */ void requestDone( PixmapRequest * request ); + void textGenerationDone( Page *page, TextPage *textPage ); /** * Request a particular metadata of the Document itself (ie, not something * depending on the document type/backend). @@ -156,8 +157,8 @@ QLinkedList< PixmapRequest * > m_pixmapRequestsStack; QLinkedList< PixmapRequest * > m_executingPixmapRequests; QMutex m_pixmapRequestsMutex; - QLinkedList< AllocatedPixmap * > m_allocatedPixmapsFifo; - qulonglong m_allocatedPixmapsTotalMemory; + QLinkedList< AllocatedData * > m_allocatedDataFifo; + qulonglong m_allocatedDataTotalMemory; bool m_warnedOutOfMemory; // the rotation applied to the document Index: core/textpage.cpp =================================================================== --- core/textpage.cpp (revision 801658) +++ core/textpage.cpp (working copy) @@ -99,6 +99,19 @@ d->m_words.append( new TextEntity( text, area ) ); } +qulonglong TextPage::aproxBytes() const +{ + qulonglong bytes = 0; + foreach(TextEntity *te, d->m_words) + { + // QString is aprox text.length * 2 + 6 + // NormalizedRect is 4 doubles + // 2 for the pointers + bytes += te->text().length() * 2 + 6 + 32 + 2; + } + return bytes; +} + RegularAreaRect * TextPage::textArea ( TextSelection * sel) const { if ( d->m_words.isEmpty() ) Index: core/document.cpp =================================================================== --- core/document.cpp (revision 801782) +++ core/document.cpp (working copy) @@ -65,6 +65,7 @@ #include "scripter.h" #include "settings.h" #include "sourcereference.h" +#include "textpage.h" #include "view.h" #include "view_p.h" @@ -72,14 +73,14 @@ using namespace Okular; -struct AllocatedPixmap +struct AllocatedData { // owner of the page - int id; + int id; // -1 is the text page int page; qulonglong memory; // public constructor: initialize data - AllocatedPixmap( int i, int p, qulonglong m ) : id( i ), page( p ), memory( m ) {} + AllocatedData( int i, int p, qulonglong m ) : id( i ), page( p ), memory( m ) {} }; struct RunningSearch @@ -157,22 +158,22 @@ switch ( Settings::memoryLevel() ) { case Settings::EnumMemoryLevel::Low: - memoryToFree = m_allocatedPixmapsTotalMemory; + memoryToFree = m_allocatedDataTotalMemory; break; case Settings::EnumMemoryLevel::Normal: { qulonglong thirdTotalMemory = getTotalMemory() / 3; qulonglong freeMemory = getFreeMemory(); - if (m_allocatedPixmapsTotalMemory > thirdTotalMemory) memoryToFree = m_allocatedPixmapsTotalMemory - thirdTotalMemory; - if (m_allocatedPixmapsTotalMemory > freeMemory) clipValue = (m_allocatedPixmapsTotalMemory - freeMemory) / 2; + if (m_allocatedDataTotalMemory > thirdTotalMemory) memoryToFree = m_allocatedDataTotalMemory - thirdTotalMemory; + if (m_allocatedDataTotalMemory > freeMemory) clipValue = (m_allocatedDataTotalMemory - freeMemory) / 2; } break; case Settings::EnumMemoryLevel::Aggressive: { qulonglong freeMemory = getFreeMemory(); - if (m_allocatedPixmapsTotalMemory > freeMemory) clipValue = (m_allocatedPixmapsTotalMemory - freeMemory) / 2; + if (m_allocatedDataTotalMemory > freeMemory) clipValue = (m_allocatedDataTotalMemory - freeMemory) / 2; } break; } @@ -184,16 +185,38 @@ { // [MEM] free memory starting from older pixmaps int pagesFreed = 0; - QLinkedList< AllocatedPixmap * >::iterator pIt = m_allocatedPixmapsFifo.begin(); - QLinkedList< AllocatedPixmap * >::iterator pEnd = m_allocatedPixmapsFifo.end(); + QLinkedList< AllocatedData * >::iterator pIt = m_allocatedDataFifo.begin(); + QLinkedList< AllocatedData * >::iterator pEnd = m_allocatedDataFifo.end(); while ( (pIt != pEnd) && (memoryToFree > 0) ) { - AllocatedPixmap * p = *pIt; - if ( m_observers.value( p->id )->canUnloadPixmap( p->page ) ) + AllocatedData * p = *pIt; + if ( p->id == -1) { + // we only unload the text if the page is not used by any of the observers + bool canUnload = true; + QMap< int, DocumentObserver * >::const_iterator it = m_observers.constBegin(); + QMap< int, DocumentObserver * >::const_iterator end = m_observers.constEnd(); + for ( ; canUnload && it != end; ++it) + { + canUnload = (*it)->canUnloadPixmap( p->page ); + } + if (canUnload) + { + pIt = m_allocatedDataFifo.erase( pIt ); + m_allocatedDataTotalMemory -= p->memory; + memoryToFree -= p->memory; + pagesFreed++; + // delete textpage + m_pagesVector.at( p->page )->setTextPage( 0 ); + // delete allocation descriptor + delete p; + } + } + else if ( m_observers.value( p->id )->canUnloadPixmap( p->page ) ) + { // update internal variables - pIt = m_allocatedPixmapsFifo.erase( pIt ); - m_allocatedPixmapsTotalMemory -= p->memory; + pIt = m_allocatedDataFifo.erase( pIt ); + m_allocatedDataTotalMemory -= p->memory; memoryToFree -= p->memory; pagesFreed++; // delete pixmap @@ -203,7 +226,7 @@ } else ++pIt; } - //p--rintf("freeMemory A:[%d -%d = %d] \n", m_allocatedPixmapsFifo.count() + pagesFreed, pagesFreed, m_allocatedPixmapsFifo.count() ); + //p--rintf("freeMemory A:[%d -%d = %d] \n", m_allocatedDataFifo.count() + pagesFreed, pagesFreed, m_allocatedDataFifo.count() ); } } @@ -575,7 +598,7 @@ { // [MEM] clean memory (for 'free mem dependant' profiles only) if ( Settings::memoryLevel() != Settings::EnumMemoryLevel::Low && - m_allocatedPixmapsTotalMemory > 1024*1024 ) + m_allocatedDataTotalMemory > 1024*1024 ) cleanupPixmapMemory(); } @@ -703,12 +726,12 @@ } // [MEM] remove allocation descriptors - QLinkedList< AllocatedPixmap * >::const_iterator aIt = m_allocatedPixmapsFifo.begin(); - QLinkedList< AllocatedPixmap * >::const_iterator aEnd = m_allocatedPixmapsFifo.end(); + QLinkedList< AllocatedData * >::const_iterator aIt = m_allocatedDataFifo.begin(); + QLinkedList< AllocatedData * >::const_iterator aEnd = m_allocatedDataFifo.end(); for ( ; aIt != aEnd; ++aIt ) delete *aIt; - m_allocatedPixmapsFifo.clear(); - m_allocatedPixmapsTotalMemory = 0; + m_allocatedDataFifo.clear(); + m_allocatedDataTotalMemory = 0; // send reload signals to observers foreachObserverD( notifyContentsCleared( DocumentObserver::Pixmap ) ); @@ -716,7 +739,7 @@ // free memory if in 'low' profile if ( Settings::memoryLevel() == Settings::EnumMemoryLevel::Low && - !m_allocatedPixmapsFifo.isEmpty() && !m_pagesVector.isEmpty() ) + !m_allocatedDataFifo.isEmpty() && !m_pagesVector.isEmpty() ) cleanupPixmapMemory(); } @@ -1568,11 +1591,11 @@ d->m_pagesVector.clear(); // clear 'memory allocation' descriptors - QLinkedList< AllocatedPixmap * >::const_iterator aIt = d->m_allocatedPixmapsFifo.begin(); - QLinkedList< AllocatedPixmap * >::const_iterator aEnd = d->m_allocatedPixmapsFifo.end(); + QLinkedList< AllocatedData * >::const_iterator aIt = d->m_allocatedDataFifo.begin(); + QLinkedList< AllocatedData * >::const_iterator aEnd = d->m_allocatedDataFifo.end(); for ( ; aIt != aEnd; ++aIt ) delete *aIt; - d->m_allocatedPixmapsFifo.clear(); + d->m_allocatedDataFifo.clear(); // clear 'running searches' descriptors QMap< int, RunningSearch * >::const_iterator rIt = d->m_searches.begin(); @@ -1594,7 +1617,7 @@ d->m_viewportHistory.clear(); d->m_viewportHistory.append( DocumentViewport() ); d->m_viewportIterator = d->m_viewportHistory.begin(); - d->m_allocatedPixmapsTotalMemory = 0; + d->m_allocatedDataTotalMemory = 0; d->m_pageSize = PageSize(); d->m_pageSizes.clear(); AudioPlayer::instance()->d->m_currentDocument = KUrl(); @@ -1625,14 +1648,14 @@ (*it)->deletePixmap( observerId ); // [MEM] free observer's allocation descriptors - QLinkedList< AllocatedPixmap * >::iterator aIt = d->m_allocatedPixmapsFifo.begin(); - QLinkedList< AllocatedPixmap * >::iterator aEnd = d->m_allocatedPixmapsFifo.end(); + QLinkedList< AllocatedData * >::iterator aIt = d->m_allocatedDataFifo.begin(); + QLinkedList< AllocatedData * >::iterator aEnd = d->m_allocatedDataFifo.end(); while ( aIt != aEnd ) { - AllocatedPixmap * p = *aIt; + AllocatedData * p = *aIt; if ( p->id == observerId ) { - aIt = d->m_allocatedPixmapsFifo.erase( aIt ); + aIt = d->m_allocatedDataFifo.erase( aIt ); delete p; } else @@ -1663,12 +1686,12 @@ } // [MEM] remove allocation descriptors - QLinkedList< AllocatedPixmap * >::const_iterator aIt = d->m_allocatedPixmapsFifo.begin(); - QLinkedList< AllocatedPixmap * >::const_iterator aEnd = d->m_allocatedPixmapsFifo.end(); + QLinkedList< AllocatedData * >::const_iterator aIt = d->m_allocatedDataFifo.begin(); + QLinkedList< AllocatedData * >::const_iterator aEnd = d->m_allocatedDataFifo.end(); for ( ; aIt != aEnd; ++aIt ) delete *aIt; - d->m_allocatedPixmapsFifo.clear(); - d->m_allocatedPixmapsTotalMemory = 0; + d->m_allocatedDataFifo.clear(); + d->m_allocatedDataTotalMemory = 0; // send reload signals to observers foreachObserver( notifyContentsCleared( DocumentObserver::Pixmap ) ); @@ -1676,7 +1699,7 @@ // free memory if in 'low' profile if ( Settings::memoryLevel() == Settings::EnumMemoryLevel::Low && - !d->m_allocatedPixmapsFifo.isEmpty() && !d->m_pagesVector.isEmpty() ) + !d->m_allocatedDataFifo.isEmpty() && !d->m_pagesVector.isEmpty() ) d->cleanupPixmapMemory(); } @@ -2188,24 +2211,24 @@ (*it)->notifyViewportChanged( smoothMove ); // [MEM] raise position of currently viewed page in allocation queue - if ( d->m_allocatedPixmapsFifo.count() > 1 ) + if ( d->m_allocatedDataFifo.count() > 1 ) { const int page = viewport.pageNumber; - QLinkedList< AllocatedPixmap * > viewportPixmaps; - QLinkedList< AllocatedPixmap * >::iterator aIt = d->m_allocatedPixmapsFifo.begin(); - QLinkedList< AllocatedPixmap * >::iterator aEnd = d->m_allocatedPixmapsFifo.end(); + QLinkedList< AllocatedData * > viewportPixmaps; + QLinkedList< AllocatedData * >::iterator aIt = d->m_allocatedDataFifo.begin(); + QLinkedList< AllocatedData * >::iterator aEnd = d->m_allocatedDataFifo.end(); while ( aIt != aEnd ) { if ( (*aIt)->page == page ) { viewportPixmaps.append( *aIt ); - aIt = d->m_allocatedPixmapsFifo.erase( aIt ); + aIt = d->m_allocatedDataFifo.erase( aIt ); continue; } ++aIt; } if ( !viewportPixmaps.isEmpty() ) - d->m_allocatedPixmapsFifo += viewportPixmaps; + d->m_allocatedDataFifo += viewportPixmaps; } } @@ -2922,14 +2945,14 @@ #endif // [MEM] 1.1 find and remove a previous entry for the same page and id - QLinkedList< AllocatedPixmap * >::iterator aIt = m_allocatedPixmapsFifo.begin(); - QLinkedList< AllocatedPixmap * >::iterator aEnd = m_allocatedPixmapsFifo.end(); + QLinkedList< AllocatedData * >::iterator aIt = m_allocatedDataFifo.begin(); + QLinkedList< AllocatedData * >::iterator aEnd = m_allocatedDataFifo.end(); for ( ; aIt != aEnd; ++aIt ) if ( (*aIt)->page == req->pageNumber() && (*aIt)->id == req->id() ) { - AllocatedPixmap * p = *aIt; - m_allocatedPixmapsFifo.erase( aIt ); - m_allocatedPixmapsTotalMemory -= p->memory; + AllocatedData * p = *aIt; + m_allocatedDataFifo.erase( aIt ); + m_allocatedDataTotalMemory -= p->memory; delete p; break; } @@ -2939,9 +2962,9 @@ { // [MEM] 1.2 append memory allocation descriptor to the FIFO qulonglong memoryBytes = 4 * req->width() * req->height(); - AllocatedPixmap * memoryPage = new AllocatedPixmap( req->id(), req->pageNumber(), memoryBytes ); - m_allocatedPixmapsFifo.append( memoryPage ); - m_allocatedPixmapsTotalMemory += memoryBytes; + AllocatedData * memoryPage = new AllocatedData( req->id(), req->pageNumber(), memoryBytes ); + m_allocatedDataFifo.append( memoryPage ); + m_allocatedDataTotalMemory += memoryBytes; // 2. notify an observer that its pixmap changed itObserver.value()->notifyPageChanged( req->pageNumber(), DocumentObserver::Pixmap ); @@ -2965,6 +2988,35 @@ sendGeneratorRequest(); } +void DocumentPrivate::textGenerationDone( Page *page, TextPage *textPage ) +{ + if ( !m_generator || m_closingLoop ) + { + delete textPage; + } + + // [MEM] 1.1 find and remove a previous entry for the same page and id + QLinkedList< AllocatedData * >::iterator aIt = m_allocatedDataFifo.begin(); + QLinkedList< AllocatedData * >::iterator aEnd = m_allocatedDataFifo.end(); + for ( ; aIt != aEnd; ++aIt ) + if ( (*aIt)->page == page->number() && (*aIt)->id == -1 ) + { + AllocatedData * p = *aIt; + m_allocatedDataFifo.erase( aIt ); + m_allocatedDataTotalMemory -= p->memory; + delete p; + break; + } + + // [MEM] 1.2 append memory allocation descriptor to the FIFO + qulonglong memoryBytes = textPage->aproxBytes(); + AllocatedData * memoryPage = new AllocatedData( -1, page->number(), memoryBytes ); + m_allocatedDataFifo.append( memoryPage ); + m_allocatedDataTotalMemory += memoryBytes; + + cleanupPixmapMemory(); +} + void Document::setRotation( int r ) { d->setRotationInternal( r, true ); @@ -3014,12 +3066,12 @@ for ( ; pIt != pEnd; ++pIt ) (*pIt)->d->changeSize( size ); // clear 'memory allocation' descriptors - QLinkedList< AllocatedPixmap * >::const_iterator aIt = d->m_allocatedPixmapsFifo.begin(); - QLinkedList< AllocatedPixmap * >::const_iterator aEnd = d->m_allocatedPixmapsFifo.end(); + QLinkedList< AllocatedData * >::const_iterator aIt = d->m_allocatedDataFifo.begin(); + QLinkedList< AllocatedData * >::const_iterator aEnd = d->m_allocatedDataFifo.end(); for ( ; aIt != aEnd; ++aIt ) delete *aIt; - d->m_allocatedPixmapsFifo.clear(); - d->m_allocatedPixmapsTotalMemory = 0; + d->m_allocatedDataFifo.clear(); + d->m_allocatedDataTotalMemory = 0; // notify the generator that the current page size has changed d->m_generator->pageSizeChanged( size, d->m_pageSize ); // set the new page size @@ -3262,3 +3314,5 @@ } #include "document.moc" + +/* kate: replace-tabs on; indent-width 4; */ Index: core/generator.cpp =================================================================== --- core/generator.cpp (revision 801658) +++ core/generator.cpp (working copy) @@ -103,6 +103,7 @@ void GeneratorPrivate::textpageGenerationFinished() { + Q_Q( Generator ); Page *page = mTextPageGenerationThread->page(); mTextPageGenerationThread->endGeneration(); @@ -121,7 +122,10 @@ } if ( mTextPageGenerationThread->textPage() ) + { page->setTextPage( mTextPageGenerationThread->textPage() ); + q->signalTextGenerationDone( page, mTextPageGenerationThread->textPage() ); + } } QMutex* GeneratorPrivate::threadsLock() @@ -234,8 +238,10 @@ void Generator::generateTextPage( Page *page ) { Q_D( Generator ); - page->setTextPage( textPage( page ) ); + TextPage *tp = textPage( page ); + page->setTextPage( tp ); d->mTextPageReady = true; + signalTextGenerationDone( page, tp ); } QImage Generator::image( PixmapRequest * ) @@ -329,6 +335,17 @@ } } +void Generator::signalTextGenerationDone( Page *page, TextPage *textPage ) +{ + Q_D( Generator ); + if ( d->m_document ) + d->m_document->textGenerationDone( page, textPage ); + else + { + delete textPage; + } +} + const Document * Generator::document() const { Q_D( const Generator ); Index: generators/poppler/generator_pdf.cpp =================================================================== --- generators/poppler/generator_pdf.cpp (revision 801658) +++ generators/poppler/generator_pdf.cpp (working copy) @@ -756,8 +756,12 @@ #else QList<Poppler::TextBox*> textList = p->textList((Poppler::Page::Rotation)request->page()->orientation()); #endif - page->setTextPage( abstractTextPage(textList, page->height(), page->width(), request->page()->orientation()) ); + Okular::TextPage *tp = abstractTextPage(textList, page->height(), page->width(), request->page()->orientation()); + page->setTextPage( tp ); qDeleteAll(textList); + + // notify the new generation + signalTextGenerationDone( page, tp ); } delete p; @@ -1573,9 +1577,13 @@ delete outImage; if ( !outText.isEmpty() ) { - request->page()->setTextPage( abstractTextPage( outText , - request->page()->height(), request->page()->width(),request->page()->orientation())); + Okular::TextPage *tp = abstractTextPage( outText, request->page()->height(), + request->page()->width(),request->page()->orientation()); + request->page()->setTextPage( tp ); qDeleteAll(outText); + + // notify the new generation + signalTextGenerationDone( request->page(), tp ); } bool genObjectRects = !rectsGenerated.at( request->page()->number() ); if (genObjectRects) @@ -1772,5 +1780,7 @@ // by ending the thread notifies the GUI thread that data is pending and can be read } + #include "generator_pdf.moc" +/* kate: replace-tabs on; indent-width 4; */
_______________________________________________ Okular-devel mailing list Okular-devel@kde.org https://mail.kde.org/mailman/listinfo/okular-devel