i18npool/inc/xdictionary.hxx                  |    6 ++++
 i18npool/source/breakiterator/xdictionary.cxx |   34 ++++++++++++++++----------
 2 files changed, 28 insertions(+), 12 deletions(-)

New commits:
commit d4370761421508522a29c5206aea6e538d71b342
Author:     Michael Weghorn <m.wegh...@posteo.de>
AuthorDate: Fri Apr 29 15:23:41 2022 +0200
Commit:     Michael Weghorn <m.wegh...@posteo.de>
CommitDate: Fri Apr 29 21:10:25 2022 +0200

    tdf#148851 Unmap + close file again in xdictionary dtor
    
    The file opened and mapped to memory in
    the `xdictionary` ctor was never unmapped
    and closed again, resulting in a memory leak.
    
    For Android Viewer, this resulted in the app
    running out of memory after a while when
    scrolling up and down in the Chinese sample
    doc from tdf#148851.
    
    On Android, closing the file is actually the relevant part,
    because the content of files from `/assets` is automatically
    loaded into memory when the files are opened (s. the call to
    `openMemoryAsFile` in `openFilePath` in `sal/osl/unx/file.cxx`)
    and that memory is only freed when the file is closed
    again (s. `osl_closeFile`).
    
    When using the sample doc, the file in question
    was "file:///assets/share/dict_zh.data", which
    has a size of 2.2 MB and is therefore actually
    loaded into memory anew every time, since only
    files below 50 KiB are handled by the file cache
    introduced in
    
        commit 26a46c1143e34e361d76d6459535c2056c59de77
        Date:   Fri Dec 20 14:46:36 2019 +0000
    
            android: file-cache to improve performance.
    
    Fix the memory leak by unmapping and closing
    the file again in the dtor.
    
    Change-Id: I3388964877080d1f2b3cf2682a41549e0bfb850c
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/133581
    Tested-by: Jenkins
    Reviewed-by: Michael Weghorn <m.wegh...@posteo.de>

diff --git a/i18npool/inc/xdictionary.hxx b/i18npool/inc/xdictionary.hxx
index cc7364bd14fc..f0861408bbd6 100644
--- a/i18npool/inc/xdictionary.hxx
+++ b/i18npool/inc/xdictionary.hxx
@@ -18,6 +18,7 @@
  */
 #pragma once
 
+#include <osl/file.h>
 #include <sal/types.h>
 
 #include <com/sun/star/i18n/Boundary.hpp>
@@ -63,6 +64,11 @@ private:
 
     css::i18n::Boundary boundary;
     bool japaneseWordBreak;
+#ifdef DICT_JA_ZH_IN_DATAFILE
+    oslFileHandle m_aFileHandle;
+    sal_uInt64 m_nFileSize;
+    char* m_pMapping;
+#endif
 
 public:
     xdictionary(const char *lang);
diff --git a/i18npool/source/breakiterator/xdictionary.cxx 
b/i18npool/source/breakiterator/xdictionary.cxx
index dd1f83f8baa7..6c326f69e48f 100644
--- a/i18npool/source/breakiterator/xdictionary.cxx
+++ b/i18npool/source/breakiterator/xdictionary.cxx
@@ -62,6 +62,11 @@ sal_Unicode* getDataArea_zh();
 
 xdictionary::xdictionary(const char *lang) :
     japaneseWordBreak( false )
+#ifdef DICT_JA_ZH_IN_DATAFILE
+    , m_aFileHandle(nullptr),
+    m_nFileSize(-1),
+    m_pMapping(nullptr)
+#endif
 {
 
 #ifdef DICT_JA_ZH_IN_DATAFILE
@@ -76,21 +81,18 @@ xdictionary::xdictionary(const char *lang) :
         else if( strcmp( lang, "zh" ) == 0 )
             sUrl += "zh.data";
 
-        oslFileHandle aFileHandle;
-        sal_uInt64 nFileSize;
-        char *pMapping;
-        if( osl_openFile( sUrl.pData, &aFileHandle, osl_File_OpenFlag_Read ) 
== osl_File_E_None &&
-            osl_getFileSize( aFileHandle, &nFileSize) == osl_File_E_None &&
-            osl_mapFile( aFileHandle, (void **) &pMapping, nFileSize, 0, 
osl_File_MapFlag_RandomAccess ) == osl_File_E_None )
+        if( osl_openFile( sUrl.pData, &m_aFileHandle, osl_File_OpenFlag_Read ) 
== osl_File_E_None &&
+            osl_getFileSize( m_aFileHandle, &m_nFileSize) == osl_File_E_None &&
+            osl_mapFile( m_aFileHandle, (void **) &m_pMapping, m_nFileSize, 0, 
osl_File_MapFlag_RandomAccess ) == osl_File_E_None )
         {
             // We have the offsets to the parts of the file at its end, see 
gendict.cxx
-            sal_Int64 *pEOF = (sal_Int64*)(pMapping + nFileSize);
+            sal_Int64 *pEOF = (sal_Int64*)(m_pMapping + m_nFileSize);
 
-            data.existMark = (sal_uInt8*) (pMapping + pEOF[-1]);
-            data.index2 = (sal_Int32*) (pMapping + pEOF[-2]);
-            data.index1 = (sal_Int16*) (pMapping + pEOF[-3]);
-            data.lenArray = (sal_Int32*) (pMapping + pEOF[-4]);
-            data.dataArea = (sal_Unicode*) (pMapping + pEOF[-5]);
+            data.existMark = (sal_uInt8*) (m_pMapping + pEOF[-1]);
+            data.index2 = (sal_Int32*) (m_pMapping + pEOF[-2]);
+            data.index1 = (sal_Int16*) (m_pMapping + pEOF[-3]);
+            data.lenArray = (sal_Int32*) (m_pMapping + pEOF[-4]);
+            data.dataArea = (sal_Unicode*) (m_pMapping + pEOF[-5]);
         }
     }
 
@@ -131,6 +133,14 @@ xdictionary::~xdictionary()
             delete [] i.wordboundary;
         }
     }
+#ifdef DICT_JA_ZH_IN_DATAFILE
+    if (m_aFileHandle) {
+        if (m_pMapping) {
+            osl_unmapMappedFile(m_aFileHandle, m_pMapping, m_nFileSize);
+        }
+        osl_closeFile(m_aFileHandle);
+    }
+#endif
 }
 
 namespace {

Reply via email to