include/o3tl/lru_map.hxx                   |   32 ++++-
 include/o3tl/numeric.hxx                   |    6 +
 include/vcl/dropcache.hxx                  |   12 +-
 include/vcl/glyphitemcache.hxx             |    7 +
 sc/source/ui/unoobj/shapeuno.cxx           |   13 +-
 sc/source/ui/view/spellcheckcontext.cxx    |   21 +++
 sw/source/core/ole/ndole.cxx               |   22 +++
 vcl/Library_vcl.mk                         |    1 
 vcl/inc/TextLayoutCache.hxx                |    6 +
 vcl/inc/graphic/Manager.hxx                |    3 
 vcl/inc/svcache.hxx                        |   52 ++++++++
 vcl/source/app/svcache.cxx                 |  174 +++++++++++++++++++++++++++++
 vcl/source/app/svdata.cxx                  |   23 +--
 vcl/source/gdi/impglyphitem.cxx            |    8 +
 vcl/source/graphic/Manager.cxx             |    5 
 vcl/source/outdev/textline.cxx             |   14 ++
 vcl/source/text/TextLayoutCache.cxx        |   30 ++++-
 vcl/unx/generic/fontmanager/fontconfig.cxx |   15 ++
 vcl/unx/generic/gdi/cairotextrender.cxx    |   35 ++++-
 19 files changed, 428 insertions(+), 51 deletions(-)

New commits:
commit b8935ee3b43e515b4a2810bb51a8bf17b90b7446
Author:     Caolán McNamara <caolan.mcnam...@collabora.com>
AuthorDate: Sun Jun 8 19:38:30 2025 +0100
Commit:     Caolán McNamara <caolan.mcnam...@collabora.com>
CommitDate: Fri Jul 4 16:47:27 2025 +0200

    use a different memory allocation strategy for caches
    
    redirect cache related allocations to the same place to attempt to put
    them in separate pages from other allocations to release that cache
    memory back to OS.
    
    Change-Id: I384658a3d652e668095b69e5a62eae5b972b5857
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/186269
    Tested-by: Caolán McNamara <caolan.mcnam...@collabora.com>
    Reviewed-by: Caolán McNamara <caolan.mcnam...@collabora.com>
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com>

diff --git a/include/o3tl/lru_map.hxx b/include/o3tl/lru_map.hxx
index 447cfcdaac86..65268ea85b4d 100644
--- a/include/o3tl/lru_map.hxx
+++ b/include/o3tl/lru_map.hxx
@@ -8,11 +8,14 @@
  *
  */
 
-#ifndef INCLUDED_O3TL_LRU_MAP_HXX
-#define INCLUDED_O3TL_LRU_MAP_HXX
+#pragma once
 
 #include <cassert>
 #include <list>
+#include <version>
+#if defined __cpp_lib_memory_resource
+#include <memory_resource>
+#endif
 #include <unordered_map>
 #include <cstddef>
 
@@ -67,11 +70,19 @@ public:
     typedef typename std::pair<Key, Value> key_value_pair_t;
 
 private:
+#if defined __cpp_lib_memory_resource
+    typedef std::pmr::list<key_value_pair_t> list_t;
+#else
     typedef std::list<key_value_pair_t> list_t;
+#endif
     typedef typename list_t::iterator list_iterator_t;
     typedef typename list_t::const_iterator list_const_iterator_t;
 
+#if defined __cpp_lib_memory_resource
+    typedef std::pmr::unordered_map<Key, list_iterator_t, KeyHash, KeyEqual> 
map_t;
+#else
     typedef std::unordered_map<Key, list_iterator_t, KeyHash, KeyEqual> map_t;
+#endif
     typedef typename map_t::iterator map_iterator_t;
     typedef typename map_t::const_iterator map_const_iterator_t;
 
@@ -169,13 +180,22 @@ public:
     {
         assert(mMaxSize > 0);
     }
+#if defined __cpp_lib_memory_resource
+    lru_map(size_t nMaxSize, std::pmr::memory_resource* r)
+        : mLruList(r)
+        , mLruMap(r)
+        , mMaxSize(nMaxSize)
+    {
+        assert(mMaxSize > 0);
+    }
+#endif
     ~lru_map()
     {
         clearSize();
         // Some code .e.g. SalBitmap likes to remove itself from a cache 
during it's destructor, which means we
         // get calls into lru_map while we are in destruction, so use the 
swap-and-clear idiom to avoid those problems.
         mLruMap.clear();
-        list_t().swap(mLruList);
+        list_t(mLruList.get_allocator()).swap(mLruList);
     }
 
     void setMaxSize(size_t nMaxSize)
@@ -286,12 +306,10 @@ public:
     void clear()
     {
         clearSize();
-        mLruMap.clear();
-        mLruList.clear();
+        map_t(mLruMap.get_allocator()).swap(mLruMap);
+        list_t(mLruList.get_allocator()).swap(mLruList);
     }
 };
 }
 
-#endif /* INCLUDED_O3TL_LRU_MAP_HXX */
-
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/include/o3tl/numeric.hxx b/include/o3tl/numeric.hxx
index 9980319a648b..0a872e8dd764 100644
--- a/include/o3tl/numeric.hxx
+++ b/include/o3tl/numeric.hxx
@@ -10,6 +10,7 @@
 #ifndef INCLUDED_O3TL_NUMERIC_HXX
 #define INCLUDED_O3TL_NUMERIC_HXX
 
+#include <bit>
 #include <stdexcept>
 
 namespace o3tl
@@ -21,6 +22,11 @@ namespace o3tl
         {
         }
     };
+
+    template<class T> constexpr unsigned int number_of_bits(T x)
+    {
+        return sizeof(T) * 8 - std::countl_zero(x);
+    }
 }
 
 #endif
diff --git a/include/vcl/dropcache.hxx b/include/vcl/dropcache.hxx
index 3a9854f203f9..588242506311 100644
--- a/include/vcl/dropcache.hxx
+++ b/include/vcl/dropcache.hxx
@@ -10,6 +10,11 @@
 #pragma once
 
 #include <vcl/dllapi.h>
+#include <rtl/ustring.hxx>
+#include <version>
+#if defined __cpp_lib_memory_resource
+#include <memory_resource>
+#endif
 
 namespace rtl
 {
@@ -23,8 +28,13 @@ protected:
     virtual ~CacheOwner();
 
 public:
-    virtual void dropCaches() = 0;
+    // returns true if cache no longer uses GetMemoryResource
+    virtual bool dropCaches() = 0;
     virtual void dumpState(rtl::OStringBuffer& rState) = 0;
+    virtual OUString getCacheName() const = 0;
+#if defined __cpp_lib_memory_resource
+    static std::pmr::memory_resource& GetMemoryResource();
+#endif
 };
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s 
cinkeys+=0=break: */
diff --git a/include/vcl/glyphitemcache.hxx b/include/vcl/glyphitemcache.hxx
index 92e427fe1aed..f6359639090f 100644
--- a/include/vcl/glyphitemcache.hxx
+++ b/include/vcl/glyphitemcache.hxx
@@ -69,7 +69,11 @@ public:
 
     static SalLayoutGlyphsCache* self();
     SalLayoutGlyphsCache(int size) // needs to be public for 
tools::DeleteOnDeinit
+#if defined __cpp_lib_memory_resource
+        : mCachedGlyphs(size, &GetMemoryResource())
+#else
         : mCachedGlyphs(size)
+#endif
     {
     }
 
@@ -96,7 +100,8 @@ public:
     };
 
 private:
-    virtual void dropCaches() override;
+    virtual OUString getCacheName() const override;
+    virtual bool dropCaches() override;
     virtual void dumpState(rtl::OStringBuffer& rState) override;
 
     struct CachedGlyphsHash
diff --git a/sc/source/ui/unoobj/shapeuno.cxx b/sc/source/ui/unoobj/shapeuno.cxx
index 88d31031e7ba..1b6f1184640f 100644
--- a/sc/source/ui/unoobj/shapeuno.cxx
+++ b/sc/source/ui/unoobj/shapeuno.cxx
@@ -232,10 +232,16 @@ struct PropertySetInfoCache : public CacheOwner
     }
 
 private:
-    virtual void dropCaches() override
+    virtual OUString getCacheName() const override
+    {
+        return "PropertySetInfoCache";
+    }
+
+    virtual bool dropCaches() override
     {
         std::unique_lock l(gCacheMutex);
-        gCacheMap.clear();
+        map_t(gCacheMap.get_allocator()).swap(gCacheMap);
+        return true;
     }
 
     virtual void dumpState(rtl::OStringBuffer& rState) override
@@ -245,7 +251,8 @@ private:
     }
 
     std::mutex gCacheMutex;
-    std::unordered_map<uno::Reference<beans::XPropertySetInfo>, 
uno::Reference<beans::XPropertySetInfo>> gCacheMap;
+    typedef std::unordered_map<uno::Reference<beans::XPropertySetInfo>, 
uno::Reference<beans::XPropertySetInfo>> map_t;
+    map_t gCacheMap;
 };
 
 }
diff --git a/sc/source/ui/view/spellcheckcontext.cxx 
b/sc/source/ui/view/spellcheckcontext.cxx
index 23b0d1dfeb4b..d3b77a5029f7 100644
--- a/sc/source/ui/view/spellcheckcontext.cxx
+++ b/sc/source/ui/view/spellcheckcontext.cxx
@@ -85,15 +85,26 @@ class SpellCheckContext::SpellCheckCache : public CacheOwner
         }
     };
 
+#if defined __cpp_lib_memory_resource
+    typedef std::pmr::unordered_map<CellPos, 
std::unique_ptr<MisspellRangesVec>, CellPos::Hash> CellMapType;
+    typedef std::pmr::unordered_map<LangSharedString, 
std::unique_ptr<MisspellRangesVec>, LangSharedString::Hash> SharedStringMapType;
+#else
     typedef std::unordered_map<CellPos, std::unique_ptr<MisspellRangesVec>, 
CellPos::Hash> CellMapType;
     typedef std::unordered_map<LangSharedString, 
std::unique_ptr<MisspellRangesVec>, LangSharedString::Hash> SharedStringMapType;
+#endif
 
     SharedStringMapType  maStringMisspells;
     CellMapType          maEditTextMisspells;
 
-    virtual void dropCaches() override
+    virtual OUString getCacheName() const override
+    {
+        return "SpellCheckCache";
+    }
+
+    virtual bool dropCaches() override
     {
         clear();
+        return true;
     }
 
     virtual void dumpState(rtl::OStringBuffer& rState) override
@@ -108,6 +119,10 @@ class SpellCheckContext::SpellCheckCache : public 
CacheOwner
 public:
 
     SpellCheckCache()
+#if defined __cpp_lib_memory_resource
+        : maStringMisspells(&CacheOwner::GetMemoryResource())
+        , maEditTextMisspells(&CacheOwner::GetMemoryResource())
+#endif
     {
     }
 
@@ -153,8 +168,8 @@ public:
 
     void clear()
     {
-        maStringMisspells.clear();
-        maEditTextMisspells.clear();
+        
SharedStringMapType(maStringMisspells.get_allocator()).swap(maStringMisspells);
+        
CellMapType(maEditTextMisspells.get_allocator()).swap(maEditTextMisspells);
     }
 
     void clearEditTextMap()
diff --git a/sw/source/core/ole/ndole.cxx b/sw/source/core/ole/ndole.cxx
index 5a8b57f5482a..6674cb1ab1a6 100644
--- a/sw/source/core/ole/ndole.cxx
+++ b/sw/source/core/ole/ndole.cxx
@@ -58,7 +58,7 @@
 #include <svx/unopage.hxx>
 #include <comphelper/threadpool.hxx>
 #include <atomic>
-#include <deque>
+#include <vector>
 #include <libxml/xmlwriter.h>
 #include <osl/diagnose.h>
 #include <flyfrm.hxx>
@@ -74,7 +74,12 @@ class SwOLELRUCache
     , public CacheOwner
 {
 private:
-    std::deque<SwOLEObj *> m_OleObjects;
+#if defined __cpp_lib_memory_resource
+    typedef std::pmr::vector<SwOLEObj*> vector_t;
+#else
+    typedef std::vector<SwOLEObj*> vector_t;
+#endif
+    vector_t m_OleObjects;
     sal_Int32 m_nLRU_InitSize;
     static uno::Sequence< OUString > GetPropertyNames();
 
@@ -82,9 +87,15 @@ private:
 
     void tryShrinkCacheTo(sal_Int32 nVal);
 
-    virtual void dropCaches() override
+    virtual OUString getCacheName() const override
+    {
+        return "SwOLELRUCache";
+    }
+
+    virtual bool dropCaches() override
     {
         tryShrinkCacheTo(0);
+        return m_OleObjects.empty();
     }
 
     virtual void dumpState(rtl::OStringBuffer& rState) override
@@ -1299,6 +1310,9 @@ void SwOLEObj::dumpAsXml(xmlTextWriterPtr pWriter) const
 
 SwOLELRUCache::SwOLELRUCache()
     : utl::ConfigItem(u"Office.Common/Cache"_ustr)
+#if defined __cpp_lib_memory_resource
+    , m_OleObjects(&GetMemoryResource())
+#endif
     , m_nLRU_InitSize( 20 )
 {
     EnableNotification( GetPropertyNames() );
@@ -1378,7 +1392,7 @@ void SwOLELRUCache::InsertObj( SwOLEObj& rObj )
         if ( pObj->UnloadObject() )
             nCount--;
     }
-    m_OleObjects.push_front(&rObj);
+    m_OleObjects.insert(m_OleObjects.begin(), &rObj);
 }
 
 void SwOLELRUCache::RemoveObj( SwOLEObj& rObj )
diff --git a/vcl/Library_vcl.mk b/vcl/Library_vcl.mk
index f8a6de5b5c2a..3dcb879b5c51 100644
--- a/vcl/Library_vcl.mk
+++ b/vcl/Library_vcl.mk
@@ -418,6 +418,7 @@ $(eval $(call gb_Library_add_exception_objects,vcl,\
     vcl/source/app/sound \
     vcl/source/app/stdtext \
     vcl/source/app/svapp \
+    vcl/source/app/svcache \
     vcl/source/app/svdata \
     vcl/source/app/svmain \
     vcl/source/app/timer \
diff --git a/vcl/inc/TextLayoutCache.hxx b/vcl/inc/TextLayoutCache.hxx
index 304c6d51ebfb..7c74e4974545 100644
--- a/vcl/inc/TextLayoutCache.hxx
+++ b/vcl/inc/TextLayoutCache.hxx
@@ -24,9 +24,11 @@
 #include <o3tl/hash_combine.hxx>
 
 #include <vcl/dllapi.h>
+#include <vcl/dropcache.hxx>
 
 #include <unicode/uscript.h>
 
+#include <new>
 #include <vector>
 
 namespace vcl::text
@@ -47,7 +49,11 @@ struct Run
 class VCL_DLLPUBLIC TextLayoutCache
 {
 public:
+#if defined __cpp_lib_memory_resource
+    std::pmr::vector<vcl::text::Run> runs;
+#else
     std::vector<vcl::text::Run> runs;
+#endif
     TextLayoutCache(sal_Unicode const* pStr, sal_Int32 const nEnd);
     // Creates a cached instance.
     static std::shared_ptr<const vcl::text::TextLayoutCache> Create(OUString 
const&);
diff --git a/vcl/inc/graphic/Manager.hxx b/vcl/inc/graphic/Manager.hxx
index efef7f5ed683..a036fc21b8a7 100644
--- a/vcl/inc/graphic/Manager.hxx
+++ b/vcl/inc/graphic/Manager.hxx
@@ -56,7 +56,8 @@ public:
     void checkStartReduceTimer();
     void reduceMemory(std::unique_lock<std::mutex>& rGuard, bool bDropAll = 
false);
     void loopAndReduceMemory(std::unique_lock<std::mutex>& rGuard, bool 
bDropAll = false);
-    virtual void dropCaches() override;
+    virtual OUString getCacheName() const override;
+    virtual bool dropCaches() override;
     virtual void dumpState(rtl::OStringBuffer& rState) override;
 };
 
diff --git a/vcl/inc/svcache.hxx b/vcl/inc/svcache.hxx
new file mode 100644
index 000000000000..5f08197619a3
--- /dev/null
+++ b/vcl/inc/svcache.hxx
@@ -0,0 +1,52 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; 
fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <rtl/alloc.h>
+#include <o3tl/numeric.hxx>
+#include <array>
+#include <map>
+#include <version>
+#if defined __cpp_lib_memory_resource
+#include <memory_resource>
+#endif
+
+#if defined __cpp_lib_memory_resource
+
+constexpr unsigned int nAlignments = 
o3tl::number_of_bits(alignof(std::max_align_t));
+
+class CacheMemory : public std::pmr::memory_resource
+{
+public:
+    CacheMemory();
+    ~CacheMemory();
+
+    static CacheMemory& GetMemoryResource();
+
+    size_t GetAllocatedPages() const;
+
+private:
+    std::array<rtl_arena_type*, nAlignments> maCacheArenas;
+    size_t mnSmallest;
+    size_t mnLargest;
+    size_t mnPageSize;
+    size_t mnAllocatedPages;
+    size_t mnMaxAllocatedPages;
+
+    static void* allocPages(rtl_arena_type* arena, sal_Size* size);
+    static void freePages(rtl_arena_type* arena, void* address, sal_Size size);
+
+    virtual void* do_allocate(std::size_t bytes, std::size_t alignment) 
override;
+    virtual void do_deallocate(void* p, std::size_t bytes, std::size_t 
alignment) override;
+    virtual bool do_is_equal(const std::pmr::memory_resource& other) const 
noexcept override;
+};
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s 
cinkeys+=0=break: */
diff --git a/vcl/source/app/svcache.cxx b/vcl/source/app/svcache.cxx
new file mode 100644
index 000000000000..6f8c2356b95c
--- /dev/null
+++ b/vcl/source/app/svcache.cxx
@@ -0,0 +1,174 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; 
fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ *   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 .
+ */
+
+#include <vcl/dropcache.hxx>
+#include <svcache.hxx>
+#include <svdata.hxx>
+#if defined SAL_UNX
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/mman.h>
+#elif defined _WIN32
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#else
+#error Unsupported platform
+#endif
+
+CacheOwner::CacheOwner()
+{
+    if (ImplSVData* pSVData = ImplGetSVData())
+    {
+        pSVData->registerCacheOwner(*this);
+        return;
+    }
+    SAL_WARN("vcl.app", "Cache owner ctor before ImplSVData created. This is 
useless.");
+}
+
+CacheOwner::~CacheOwner()
+{
+    if (ImplSVData* pSVData = ImplGetSVData())
+        pSVData->deregisterCacheOwner(*this);
+}
+
+#if defined __cpp_lib_memory_resource
+
+#define MEMORY_ALIGN(value, align) (((value) + ((align)-1)) & ~((align)-1))
+
+void* CacheMemory::allocPages(rtl_arena_type* arena, sal_Size* size)
+{
+    CacheMemory* pCacheMemory = reinterpret_cast<CacheMemory*>(arena);
+
+    std::size_t n = MEMORY_ALIGN(*size, pCacheMemory->mnPageSize);
+    void* p;
+#if defined SAL_UNX
+    p = mmap(nullptr, n, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 
0);
+    if (p == MAP_FAILED)
+        p = nullptr;
+#elif defined _WIN32
+    p = VirtualAlloc(nullptr, n, MEM_COMMIT, PAGE_READWRITE);
+#endif
+    if (p != nullptr)
+    {
+        pCacheMemory->mnAllocatedPages += (n / pCacheMemory->mnPageSize);
+        pCacheMemory->mnMaxAllocatedPages
+            = std::max(pCacheMemory->mnMaxAllocatedPages, 
pCacheMemory->mnAllocatedPages);
+        *size = n;
+    }
+    return p;
+}
+
+void CacheMemory::freePages(rtl_arena_type* arena, void* address, sal_Size 
size)
+{
+    CacheMemory* pCacheMemory = reinterpret_cast<CacheMemory*>(arena);
+#if defined SAL_UNX
+    munmap(address, size);
+#elif defined _WIN32
+    (void)size; // unused
+    VirtualFree(address, 0, MEM_RELEASE);
+#endif
+    pCacheMemory->mnAllocatedPages -= (size / pCacheMemory->mnPageSize);
+}
+
+CacheMemory::CacheMemory()
+    : maCacheArenas{ nullptr }
+    , mnSmallest(SAL_MAX_SIZE)
+    , mnLargest(0)
+    , mnAllocatedPages(0)
+    , mnMaxAllocatedPages(0)
+{
+#if defined SAL_UNX
+#if defined FREEBSD || defined NETBSD || defined OPENBSD || defined DRAGONFLY 
|| defined HAIKU
+    mnPageSize = getpagesize();
+#else
+    // coverity[ tainted_data_return : FALSE ] version 2023.12.2
+    mnPageSize = sysconf(_SC_PAGESIZE);
+#endif
+#elif defined _WIN32
+    SYSTEM_INFO info;
+    GetSystemInfo(&info);
+    mnPageSize = info.dwPageSize;
+#else
+#error Unsupported platform
+#endif
+}
+
+size_t CacheMemory::GetAllocatedPages() const { return mnAllocatedPages; }
+
+CacheMemory::~CacheMemory()
+{
+    SAL_INFO("vcl", "cachememory, smallest/largest are: "
+                        << mnSmallest << ", " << mnLargest << "total pages 
allocated: "
+                        << mnMaxAllocatedPages << ", current allocated pages" 
<< mnAllocatedPages);
+    for (size_t i = 0; i < maCacheArenas.size(); ++i)
+    {
+        if (!maCacheArenas[i])
+            continue;
+        SAL_INFO("vcl", "cachememory, destroying arena for alignment: " << (1 
<< i));
+        rtl_arena_destroy(maCacheArenas[i]);
+    }
+}
+
+void* CacheMemory::do_allocate(std::size_t bytes, std::size_t alignment)
+{
+    alignment = std::max<std::size_t>(alignment, 4);
+    const unsigned int nSlot = o3tl::number_of_bits(alignment) - 1;
+    if (!maCacheArenas[nSlot])
+    {
+        maCacheArenas[nSlot]
+            = rtl_arena_create("cache_internal_arena", alignment, 0,
+                               reinterpret_cast<rtl_arena_type*>(this), 
allocPages, freePages, 0);
+    }
+
+    mnSmallest = std::min(mnSmallest, bytes);
+    mnLargest = std::max(mnLargest, bytes);
+    sal_Size size = MEMORY_ALIGN(bytes, alignment);
+    return rtl_arena_alloc(maCacheArenas[nSlot], &size);
+}
+
+void CacheMemory::do_deallocate(void* p, std::size_t bytes, std::size_t 
alignment)
+{
+    alignment = std::max<std::size_t>(alignment, 4);
+    const unsigned int nSlot = o3tl::number_of_bits(alignment) - 1;
+    sal_Size size = MEMORY_ALIGN(bytes, alignment);
+    rtl_arena_free(maCacheArenas[nSlot], p, size);
+}
+
+bool CacheMemory::do_is_equal(const std::pmr::memory_resource& other) const 
noexcept
+{
+    SAL_WARN("vcl", "CacheMemory::do_is_equal called");
+    return &other == this;
+}
+
+//static
+CacheMemory& CacheMemory::GetMemoryResource()
+{
+    static CacheMemory aCacheMemory;
+    return aCacheMemory;
+}
+
+//static
+std::pmr::memory_resource& CacheOwner::GetMemoryResource()
+{
+    return CacheMemory::GetMemoryResource();
+}
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s 
cinkeys+=0=break: */
diff --git a/vcl/source/app/svdata.cxx b/vcl/source/app/svdata.cxx
index 303e01dbfca4..912de070fad3 100644
--- a/vcl/source/app/svdata.cxx
+++ b/vcl/source/app/svdata.cxx
@@ -44,6 +44,7 @@
 #include <vcl/toolkit/dialog.hxx>
 #include <salinst.hxx>
 #include <salgdi.hxx>
+#include <svcache.hxx>
 #include <svdata.hxx>
 #include <salsys.hxx>
 #include <windowdev.hxx>
@@ -448,24 +449,18 @@ void ImplSVData::dropCaches()
 
     // copy, some caches self-delete on emptying, e.g. SwOLELRUCache
     auto aCacheOwners = maCacheOwners;
+    bool bAllCachesDropped = true;
     for (CacheOwner* pCacheOwner : aCacheOwners)
-        pCacheOwner->dropCaches();
-}
-
-CacheOwner::CacheOwner()
-{
-    if (ImplSVData* pSVData = ImplGetSVData())
     {
-        pSVData->registerCacheOwner(*this);
-        return;
+        bool bCacheDropped = pCacheOwner->dropCaches();
+        SAL_WARN_IF(!bCacheDropped, "vcl", "Cache " << 
pCacheOwner->getCacheName() << " drop failed");
+        bAllCachesDropped &= bCacheDropped;
     }
-    SAL_WARN("vcl.app", "Cache owner ctor before ImplSVData created. This is 
useless.");
-}
 
-CacheOwner::~CacheOwner()
-{
-    if (ImplSVData* pSVData = ImplGetSVData())
-        pSVData->deregisterCacheOwner(*this);
+#if defined __cpp_lib_memory_resource
+    assert(!bAllCachesDropped || 
CacheMemory::GetMemoryResource().GetAllocatedPages() == 0);
+#endif
+    (void)bAllCachesDropped;
 }
 
 void ImplSVData::dumpState(rtl::OStringBuffer &rState)
diff --git a/vcl/source/gdi/impglyphitem.cxx b/vcl/source/gdi/impglyphitem.cxx
index 78137c73370e..a8e72bbc30f0 100644
--- a/vcl/source/gdi/impglyphitem.cxx
+++ b/vcl/source/gdi/impglyphitem.cxx
@@ -590,7 +590,13 @@ size_t SalLayoutGlyphsCache::GlyphsCost::operator()(const 
SalLayoutGlyphs& glyph
     return cost;
 }
 
-void SalLayoutGlyphsCache::dropCaches() { clear(); }
+OUString SalLayoutGlyphsCache::getCacheName() const { return 
"SalLayoutGlyphsCache"; }
+
+bool SalLayoutGlyphsCache::dropCaches()
+{
+    clear();
+    return true;
+}
 
 void SalLayoutGlyphsCache::dumpState(rtl::OStringBuffer& rState)
 {
diff --git a/vcl/source/graphic/Manager.cxx b/vcl/source/graphic/Manager.cxx
index 17f25cedec7c..bafa2711cbff 100644
--- a/vcl/source/graphic/Manager.cxx
+++ b/vcl/source/graphic/Manager.cxx
@@ -119,10 +119,13 @@ void MemoryManager::swappedOut(MemoryManaged* 
pMemoryManaged, sal_Int64 nNewSize
     changeExisting(pMemoryManaged, nNewSize);
 }
 
-void MemoryManager::dropCaches()
+OUString MemoryManager::getCacheName() const { return "MemoryManager"; }
+
+bool MemoryManager::dropCaches()
 {
     std::unique_lock aGuard(maMutex);
     reduceMemory(aGuard, true);
+    return true;
 }
 
 void MemoryManager::dumpState(rtl::OStringBuffer& rState)
diff --git a/vcl/source/outdev/textline.cxx b/vcl/source/outdev/textline.cxx
index 87a2591ab77c..df9e42fd34e6 100644
--- a/vcl/source/outdev/textline.cxx
+++ b/vcl/source/outdev/textline.cxx
@@ -43,7 +43,14 @@
 namespace {
     struct WavyLineCache final : public CacheOwner
     {
-        WavyLineCache () : m_aItems( 10 ) {}
+        WavyLineCache()
+#if defined __cpp_lib_memory_resource
+            : m_aItems(10, &GetMemoryResource())
+#else
+            : m_aItems(10)
+#endif
+        {
+        }
 
         bool find( Color aLineColor, size_t nLineWidth, size_t nWaveHeight, 
size_t nWordWidth, BitmapEx& rOutput )
         {
@@ -67,9 +74,12 @@ namespace {
             rOutput = aBitmap;
         }
 
-        virtual void dropCaches() override
+        virtual OUString getCacheName() const override { return 
"WavyLineCache"; }
+
+        virtual bool dropCaches() override
         {
             m_aItems.clear();
+            return true;
         }
 
         virtual void dumpState(rtl::OStringBuffer& rState) override
diff --git a/vcl/source/text/TextLayoutCache.cxx 
b/vcl/source/text/TextLayoutCache.cxx
index 1a7c6ab521cf..b4f3799802a5 100644
--- a/vcl/source/text/TextLayoutCache.cxx
+++ b/vcl/source/text/TextLayoutCache.cxx
@@ -29,9 +29,14 @@
 #include <officecfg/Office/Common.hxx>
 #include <vcl/dropcache.hxx>
 
+#include <memory>
+
 namespace vcl::text
 {
 TextLayoutCache::TextLayoutCache(sal_Unicode const* pStr, sal_Int32 const nEnd)
+#if defined __cpp_lib_memory_resource
+    : runs(&CacheOwner::GetMemoryResource())
+#endif
 {
     vcl::ScriptRun aScriptRun(reinterpret_cast<const UChar*>(pStr), nEnd);
     while (aScriptRun.next())
@@ -57,10 +62,18 @@ struct TextLayoutCacheMap : public CacheOwner
                           FastStringCompareEqual, TextLayoutCacheCost>
         Cache;
 
+#if defined __cpp_lib_memory_resource
+    std::pmr::polymorphic_allocator<TextLayoutCache> allocator;
+#endif
     Cache cache;
 
     TextLayoutCacheMap(int capacity)
+#if defined __cpp_lib_memory_resource
+        : allocator(&CacheOwner::GetMemoryResource())
+        , cache(capacity, &CacheOwner::GetMemoryResource())
+#else
         : cache(capacity)
+#endif
     {
     }
 
@@ -69,12 +82,23 @@ struct TextLayoutCacheMap : public CacheOwner
         auto it = cache.find(rString);
         if (it != cache.end())
             return it->second;
-        auto ret = std::make_shared<const TextLayoutCache>(rString.getStr(), 
rString.getLength());
+#if defined __cpp_lib_memory_resource
+        auto ret = std::allocate_shared<TextLayoutCache>(allocator, 
rString.getStr(),
+                                                         rString.getLength());
+#else
+        auto ret = std::make_shared<TextLayoutCache>(rString.getStr(), 
rString.getLength());
+#endif
         cache.insert({ rString, ret });
         return ret;
     }
 
-    virtual void dropCaches() override { cache.clear(); }
+    virtual OUString getCacheName() const override { return "TextLayoutCache"; 
}
+
+    virtual bool dropCaches() override
+    {
+        cache.clear();
+        return true;
+    }
 
     virtual void dumpState(rtl::OStringBuffer& rState) override
     {
@@ -100,7 +124,7 @@ std::shared_ptr<const TextLayoutCache> 
TextLayoutCache::Create(OUString const& r
                                  : 100);
     if (TextLayoutCacheMap* map = cache.get())
         return map->Create(rString);
-    return std::make_shared<const TextLayoutCache>(rString.getStr(), 
rString.getLength());
+    return std::make_shared<TextLayoutCache>(rString.getStr(), 
rString.getLength());
 }
 }
 
diff --git a/vcl/unx/generic/fontmanager/fontconfig.cxx 
b/vcl/unx/generic/fontmanager/fontconfig.cxx
index 80054e28bc7f..95ed5a19b5fc 100644
--- a/vcl/unx/generic/fontmanager/fontconfig.cxx
+++ b/vcl/unx/generic/fontmanager/fontconfig.cxx
@@ -121,7 +121,12 @@ private:
 
 public:
     CachedFontConfigFontOptions()
-        : lru_options_cache(10) // arbitrary cache size of 10
+        // arbitrary cache size of 10
+#if defined __cpp_lib_memory_resource
+        : lru_options_cache(10, &CacheOwner::GetMemoryResource())
+#else
+        : lru_options_cache(10)
+#endif
     {
     }
 
@@ -139,9 +144,15 @@ public:
     }
 
 private:
-    virtual void dropCaches() override
+    virtual OUString getCacheName() const override
+    {
+        return "CachedFontConfigFontOptions";
+    }
+
+    virtual bool dropCaches() override
     {
         lru_options_cache.clear();
+        return true;
     }
 
     virtual void dumpState(rtl::OStringBuffer& rState) override
diff --git a/vcl/unx/generic/gdi/cairotextrender.cxx 
b/vcl/unx/generic/gdi/cairotextrender.cxx
index 80110829d99a..a5afbbe2d93f 100644
--- a/vcl/unx/generic/gdi/cairotextrender.cxx
+++ b/vcl/unx/generic/gdi/cairotextrender.cxx
@@ -62,12 +62,22 @@ public:
     };
 
 private:
-    typedef std::deque< std::pair<cairo_font_face_t*, CacheId> > LRUFonts;
+#if defined __cpp_lib_memory_resource
+    typedef std::pmr::vector< std::pair<cairo_font_face_t*, CacheId> > 
LRUFonts;
+#else
+    typedef std::vector< std::pair<cairo_font_face_t*, CacheId> > LRUFonts;
+#endif
     LRUFonts maLRUFonts;
 
-    virtual void dropCaches() override
+    virtual OUString getCacheName() const override
+    {
+        return "CairoFontsCache";
+    }
+
+    virtual bool dropCaches() override
     {
-        maLRUFonts.clear();
+        LRUFonts(maLRUFonts.get_allocator()).swap(maLRUFonts);
+        return true;
     }
 
     virtual void dumpState(rtl::OStringBuffer& rState) override
@@ -77,6 +87,15 @@ private:
     }
 
 public:
+    CairoFontsCache()
+#if defined __cpp_lib_memory_resource
+        : maLRUFonts(&CacheOwner::GetMemoryResource())
+#else
+        : maLRUFonts()
+#endif
+    {
+    }
+
     void               CacheFont(cairo_font_face_t* pFont, const CacheId &rId);
     cairo_font_face_t* FindCachedFont(const CacheId &rId);
 };
@@ -89,19 +108,19 @@ CairoFontsCache& getCairoFontsCache()
 
 void CairoFontsCache::CacheFont(cairo_font_face_t* pFont, const 
CairoFontsCache::CacheId &rId)
 {
-    maLRUFonts.push_front( std::pair<cairo_font_face_t*, 
CairoFontsCache::CacheId>(pFont, rId) );
+    maLRUFonts.push_back( std::pair<cairo_font_face_t*, 
CairoFontsCache::CacheId>(pFont, rId) );
     if (maLRUFonts.size() > 8)
     {
-        cairo_font_face_destroy(maLRUFonts.back().first);
-        maLRUFonts.pop_back();
+        cairo_font_face_destroy(maLRUFonts.front().first);
+        maLRUFonts.erase(maLRUFonts.begin());
     }
 }
 
 cairo_font_face_t* CairoFontsCache::FindCachedFont(const 
CairoFontsCache::CacheId &rId)
 {
-    auto aI = std::find_if(maLRUFonts.begin(), maLRUFonts.end(),
+    auto aI = std::find_if(maLRUFonts.rbegin(), maLRUFonts.rend(),
         [&rId](const LRUFonts::value_type& rFont) { return rFont.second == 
rId; });
-    if (aI != maLRUFonts.end())
+    if (aI != maLRUFonts.rend())
         return aI->first;
     return nullptr;
 }

Reply via email to