diff options
author | Armin Le Grand <alg@apache.org> | 2014-06-19 16:49:26 +0000 |
---|---|---|
committer | Armin Le Grand <alg@apache.org> | 2014-06-19 16:49:26 +0000 |
commit | 61b32a70c92ee1b1148bcd9788561b79dc1910c8 (patch) | |
tree | 4e1c64a4032ddb4bbf1fc2bffea0a1a47b2473ca /svtools | |
parent | c20e4c606988de65d45ce3ce9608cb75deb5234a (diff) |
i125111 limit mem footprint for GraphicObjects in 32Bit environments
Notes
Notes:
merged as: 0ca0202a0994c0b7c99c366fd5cafd8a655df203
Diffstat (limited to 'svtools')
-rw-r--r-- | svtools/inc/svtools/grfmgr.hxx | 24 | ||||
-rw-r--r-- | svtools/source/graphic/grfmgr.cxx | 47 | ||||
-rw-r--r-- | svtools/source/graphic/grfmgr2.cxx | 72 |
3 files changed, 141 insertions, 2 deletions
diff --git a/svtools/inc/svtools/grfmgr.hxx b/svtools/inc/svtools/grfmgr.hxx index ca2e10b20fd1..a30df40c577c 100644 --- a/svtools/inc/svtools/grfmgr.hxx +++ b/svtools/inc/svtools/grfmgr.hxx @@ -207,7 +207,10 @@ private: Timer* mpSwapOutTimer; GrfSimpleCacheObj* mpSimpleCache; sal_uLong mnAnimationLoopCount; - void* mpDummy1; + + // a unique increasing ID to be able to say which data change is older + sal_uLong mnDataChangeTimeStamp; + void* mpDummy2; sal_Bool mbAutoSwapped : 1; sal_Bool mbTransparent : 1; @@ -299,6 +302,10 @@ private: DECL_LINK( ImplAutoSwapOutHdl, void* ); + // Handle evtl. needed AfterDataChanges, needs to be called when new + // graphic data is swapped in/added to the GraphicManager + void ImplAfterDataChange(); + protected: virtual void GraphicManagerDestroyed(); @@ -481,6 +488,12 @@ public: double fTopCrop, double fRightCrop, double fBottomCrop) const; + + // read access + sal_uLong GetDataChangeTimeStamp() const { return mnDataChangeTimeStamp; } + + // restart SwapOut timer; this is like touching in a cache to reset to the full timeout value + void restartSwapOutTimer() const; }; // ------------------ @@ -545,6 +558,15 @@ private: ByteString SVT_DLLPRIVATE ImplGetUniqueID( const GraphicObject& rObj ) const; + // This method allows to check memory footprint for all currently swapped in GraphicObjects on this GraphicManager + // which are based on Bitmaps. This is needed on 32Bit systems and only does something on those systems. The problem + // to solve is that normally the SwapOut is timer-driven, but even with short timer settings there are situations + // where this does not trigger - or in other words: A maximum limitation for GraphicManagers was not in place before. + // For 32Bit systems this leads to situations where graphics will be missing. This method will actively swap out + // the longest swapped in graphics until a maximum memory boundary (derived from user settings in tools/options/memory) + // is no longer exceeded + void ImplCheckSizeOfSwappedInGraphics(); + public: GraphicManager( sal_uLong nCacheSize = 10000000UL, sal_uLong nMaxObjCacheSize = 2400000UL ); diff --git a/svtools/source/graphic/grfmgr.cxx b/svtools/source/graphic/grfmgr.cxx index 59dc21b074f5..00cfcc0506f0 100644 --- a/svtools/source/graphic/grfmgr.cxx +++ b/svtools/source/graphic/grfmgr.cxx @@ -76,6 +76,19 @@ struct GrfSimpleCacheObj TYPEINIT1_AUTOFACTORY( GraphicObject, SvDataCopyStream ); +// unique increasing ID for being able to detect the GraphicObject with the +// oldest last data changes +static sal_uLong aIncrementingTimeOfLastDataChange = 1; + +void GraphicObject::ImplAfterDataChange() +{ + // set unique timestamp ID of last data change + mnDataChangeTimeStamp = aIncrementingTimeOfLastDataChange++; + + // check memory footprint of all GraphicObjects managed and evtl. take action + GetGraphicManager().ImplCheckSizeOfSwappedInGraphics(); +} + // ----------------------------------------------------------------------------- GraphicObject::GraphicObject( const GraphicManager* pMgr ) : @@ -173,6 +186,9 @@ void GraphicObject::ImplConstruct() mbAutoSwapped = sal_False; mbIsInSwapIn = sal_False; mbIsInSwapOut = sal_False; + + // Init with a unique, increasing ID + mnDataChangeTimeStamp = aIncrementingTimeOfLastDataChange++; } // ----------------------------------------------------------------------------- @@ -290,6 +306,9 @@ void GraphicObject::ImplAutoSwapIn() if( !mbAutoSwapped && mpMgr ) mpMgr->ImplGraphicObjectWasSwappedIn( *this ); } + + // Handle evtl. needed AfterDataChanges + ImplAfterDataChange(); } } @@ -914,6 +933,9 @@ void GraphicObject::SetGraphic( const Graphic& rGraphic, const GraphicObject* pC if( mpSwapOutTimer ) mpSwapOutTimer->Start(); + + // Handle evtl. needed AfterDataChanges + ImplAfterDataChange(); } // ----------------------------------------------------------------------------- @@ -1255,7 +1277,9 @@ sal_Bool GraphicObject::SwapIn() bRet = sal_True; } else if( mpMgr && mpMgr->ImplFillSwappedGraphicObject( *this, maGraphic ) ) + { bRet = sal_True; + } else { bRet = maGraphic.SwapIn(); @@ -1265,8 +1289,13 @@ sal_Bool GraphicObject::SwapIn() } if( bRet ) + { ImplAssignGraphicData(); + // Handle evtl. needed AfterDataChanges + ImplAfterDataChange(); + } + return bRet; } @@ -1282,7 +1311,9 @@ sal_Bool GraphicObject::SwapIn( SvStream* pIStm ) bRet = sal_True; } else if( mpMgr && mpMgr->ImplFillSwappedGraphicObject( *this, maGraphic ) ) + { bRet = sal_True; + } else { bRet = maGraphic.SwapIn( pIStm ); @@ -1292,8 +1323,13 @@ sal_Bool GraphicObject::SwapIn( SvStream* pIStm ) } if( bRet ) + { ImplAssignGraphicData(); + // + ImplAfterDataChange(); + } + return bRet; } @@ -1453,4 +1489,15 @@ basegfx::B2DVector GraphicObject::calculateCropScaling( return basegfx::B2DVector(fFactorX,fFactorY); } +// ------------------------------------------------------------------------ +// restart SwapOut timer + +void GraphicObject::restartSwapOutTimer() const +{ + if( mpSwapOutTimer && mpSwapOutTimer->IsActive() ) + { + mpSwapOutTimer->Start(); + } +} + // eof diff --git a/svtools/source/graphic/grfmgr2.cxx b/svtools/source/graphic/grfmgr2.cxx index c599a1d3f48d..c8532bb21efa 100644 --- a/svtools/source/graphic/grfmgr2.cxx +++ b/svtools/source/graphic/grfmgr2.cxx @@ -295,9 +295,79 @@ ByteString GraphicManager::ImplGetUniqueID( const GraphicObject& rObj ) const // ----------------------------------------------------------------------------- +void GraphicManager::ImplCheckSizeOfSwappedInGraphics() +{ + // only necessary for 32bit systems + if(SAL_TYPES_SIZEOFPOINTER <= 4) + { + // get the currently used memory footprint of all swapped in bitmap graphics + // of this graphic manager. Remember candidates in a vector. The size in bytes is + // already available, thus this loop is not expensive to execute + sal_uLong nUsedSize(0); + GraphicObject* pObj = 0; + std::vector< GraphicObject* > aCandidates; + + for(pObj = (GraphicObject*)maObjList.First(); pObj; pObj = (GraphicObject*)maObjList.Next()) + { + if(pObj->meType == GRAPHIC_BITMAP && !pObj->IsSwappedOut() && pObj->GetSizeBytes()) + { + aCandidates.push_back(pObj); + nUsedSize += pObj->GetSizeBytes(); + } + } + + // detect maximum allowed memory footprint. Use the user-settings of MaxCacheSize (defaulted + // to 20MB) and add a decent multiplicator (expecrimented to find one). Limit to + // a useful maximum for 32Bit address space + + // default is 20MB, so allow 200MB initially + static sal_uLong aMultiplicator(10); + + // max at 500MB; I experimented with 800 for debug and 750 for non-debug settings (pics start + // missing when AOO reaches a mem footprint of 1.5GB) but some secure left over space for + // app activity is needed + static sal_uLong aMaxSize32Bit(500 * 1024 * 1024); + + // calc max allowed cache size + const sal_uLong nMaxCacheSize(::std::min(GetMaxCacheSize() * aMultiplicator, aMaxSize32Bit)); + + if(nUsedSize >= nMaxCacheSize && !aCandidates.empty()) + { + // if we use more currently, sort by last DataChangeTimeStamp + struct simpleSortByDataChangeTimeStamp + { + bool operator() (GraphicObject* p1, GraphicObject* p2) const + { + return p1->GetDataChangeTimeStamp() < p2->GetDataChangeTimeStamp(); + } + }; + + // sort by DataChangeTimeStamp so that the oldest get removed first + ::std::sort(aCandidates.begin(), aCandidates.end(), simpleSortByDataChangeTimeStamp()); + + for(sal_uInt32 a(0); nUsedSize >= nMaxCacheSize && a < aCandidates.size(); a++) + { + // swap out until we have no more or the goal to use less than nMaxCacheSize + // is reached + pObj = aCandidates[a]; + const sal_uLong nSizeBytes(pObj->GetSizeBytes()); + + // do not swap out when we have less than 16KB data objects + if(nSizeBytes >= (16 * 1024)) + { + pObj->FireSwapOutRequest(); + nUsedSize = (nSizeBytes < nUsedSize) ? nUsedSize - nSizeBytes : 0; + } + } + } + } +} + +// ----------------------------------------------------------------------------- + sal_Bool GraphicManager::ImplFillSwappedGraphicObject( const GraphicObject& rObj, Graphic& rSubstitute ) { - return( mpCache->FillSwappedGraphicObject( rObj, rSubstitute ) ); + return mpCache->FillSwappedGraphicObject(rObj, rSubstitute); } // ----------------------------------------------------------------------------- |