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

Reply via email to