[UWP][C++/WINRT] Massive memory leaks?

Elliot 6 Reputation points
2020-09-30T10:13:32.153+00:00

Revised question:
Do UWP file operations have memory leaks? Below I have the C++/winrt and c#/winrt versions of an example where we get the StorageFile objects of c:/program files (recursive). This takes a long time to run, and there appears to be a large memory leak amounting to tens of megabytes or more on my machine.

c# version:

using System;  
using System.Collections.Generic;  
using System.IO;  
using System.Linq;  
using System.Runtime.InteropServices.WindowsRuntime;  
using Windows.Foundation;  
using Windows.Foundation.Collections;  
using Windows.UI.Xaml;  
using Windows.UI.Xaml.Controls;  
using Windows.UI.Xaml.Controls.Primitives;  
using Windows.UI.Xaml.Data;  
using Windows.UI.Xaml.Input;  
using Windows.UI.Xaml.Media;  
using Windows.UI.Xaml.Navigation;  
using System.Diagnostics;  
  
// The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409  
  
namespace MemoryLeak001_CSharp_2  
{  
    /// <summary>  
    /// An empty page that can be used on its own or navigated to within a Frame.  
    /// </summary>  
    public sealed partial class MainPage : Page  
    {  
        public MainPage()  
        {  
            this.InitializeComponent();  
 
        }  



       // Can take a very long time  
        private async void Button_Click(object sender, RoutedEventArgs e)  
        {  
  
            GC.Collect();  
  
            Trace.WriteLine("\nButton_Click started...\n");  
            {  
                Windows.Storage.StorageFolder _root = await Windows.Storage.StorageFolder.GetFolderFromPathAsync("C:\\program files");  
                 
                    var _storageFiles = await _root.GetFilesAsync(Windows.Storage.Search.CommonFileQuery.OrderByName);  
                var _count = _storageFiles.Count;  
            }  
  
            GC.Collect();  
            GC.WaitForPendingFinalizers();  
            Trace.WriteLine("\nButton_Click finished.\n");  
  
        }  
    }  
}  

c

c++ version:

#include "pch.h"  
#include <thread>  
#include <winrt/Windows.Storage.h>  
#include <winrt/Windows.Storage.Streams.h>  
#include <winrt/Windows.Foundation.Collections.h>  
#include <winrt/Windows.Storage.Search.h>  
  
using namespace winrt;  
using namespace Windows::Foundation;  
using namespace winrt::Windows::Storage::Streams;  
using namespace winrt::Windows::Storage::Search;  
  
  
  
int main()  
{  
    init_apartment();  
  
    __int64 _count{ -1 };  
  
    {  
        winrt::Windows::Storage::StorageFolder _root = winrt::Windows::Storage::StorageFolder::GetFolderFromPathAsync(L"c:\\program files\\").get();  
        auto _storageFiles = _root.GetFilesAsync(CommonFileQuery::OrderByName).get();  
        _count = _storageFiles.Size();  
    }  
  
    // The file-open stuff has gone out of scope now.  
    //Uri uri(L"http://aka.ms/cppwinrt");  
    printf("Count: %d", _count);  
}  

----------

Old version of question:

With the async functions, such as for opening files, I have experimented with using co_await, .Completed(...) and also .get() to do the same things.̶F̶o̶r̶ ̶.̶g̶e̶t̶(̶)̶ ̶I̶ ̶t̶h̶i̶n̶k̶ ̶I̶ ̶a̶m̶ ̶g̶e̶t̶t̶i̶n̶g̶ ̶q̶u̶i̶t̶e̶ ̶a̶ ̶l̶o̶t̶ ̶o̶f̶ ̶m̶e̶m̶o̶r̶y̶ ̶l̶e̶a̶k̶.̶ Update: I don't think it's just get(); seems to be file operations in general. In the example below I open a large file (~1.5GB). There seems to be a residual of heap memory usage, amounting to over 300kB in this case. Am I wrong in thinking that this is a memory leak?

#include "pch.h"  
#include <thread>  
#include <winrt/Windows.Storage.h>  
#include <winrt/Windows.Storage.Streams.h>  
  
using namespace winrt;  
using namespace Windows::Foundation;  
  
int main()  
{  
 init_apartment();  
  
 {  
 winrt::Windows::Storage::StorageFile _storageFile = winrt::Windows::Storage::StorageFile::GetFileFromPathAsync(L"C:\\The Crush (1993) [1080p] [YTS.AG]\\The.Crush.1993.1080p.BluRay.x264-[YTS.AG].mp4").get();  
 using namespace winrt::Windows::Storage::Streams;  
 IRandomAccessStreamWithContentType _stream = _storageFile.OpenReadAsync().get();  
 const size_t _fileSize = _stream.Size();  
 std::vector<uint8_t>_buffer(_fileSize);  
 using namespace Windows::Storage::Streams;  
 const IInputStream _inputStream = _stream.GetInputStreamAt(0);  
 const IDataReader _dataReader = winrt::Windows::Storage::Streams::DataReader(_inputStream);  
 const uint32_t _loadTask = _dataReader.LoadAsync(_fileSize).get();  
 _dataReader.ReadBytes(_buffer);  
 }  
 // The file-open stuff has gone out of scope now.  
    Uri uri(L"http://aka.ms/cppwinrt");  
    printf("Hello, %ls!\n", uri.AbsoluteUri().c_str());  
 while (true)  
 {  
 std::this_thread::sleep_for(std::chrono::milliseconds(20));  
 }  
}  
  

29408-memoryleak003.png

UPDATE:
Another example:

#include "pch.h"  
#include <thread>  
#include <winrt/Windows.Storage.h>  
#include <winrt/Windows.Storage.Streams.h>  
#include <winrt/Windows.Foundation.Collections.h>  
#include <winrt/Windows.Storage.Search.h>  
  
using namespace winrt;  
using namespace Windows::Foundation;  
using namespace winrt::Windows::Storage::Streams;  
using namespace winrt::Windows::Storage::Search;  
  
  
int main()  
{  
    init_apartment();  
  
    {  
        winrt::Windows::Storage::StorageFolder _root = winrt::Windows::Storage::StorageFolder::GetFolderFromPathAsync(L"c:\\program files\\").get();  
        auto _storageFiles = _root.GetFilesAsync(CommonFileQuery::OrderByName).get();  
    }  
  
    // The file-open stuff has gone out of scope now.  
    Uri uri(L"http://aka.ms/cppwinrt");  
    printf("Hello, %ls!\n", uri.AbsoluteUri().c_str());  
}  

The memory usage peaks at 1.2 gig for me, and quite a lot is leaked afterwards as well. I think the peak worked out at 40k per StorageFile. I tried using umdh to shed some light on this. Here are some of the biggest residuals:

  • 3d400 ( 3d400 - 0) 38 allocs BackTrace37D71046
  •  38 (    38 -     0) BackTrace37D71046 allocations    
    

ntdll!RtlpCallInterceptRoutine+3F
ntdll!RtlpAllocateHeapInternal+78B6B
combase!CInternalPageAllocator::Grow+3B (onecore\com\combase\coll\pgalloc.cxx, 348)
combase!CPageAllocator::AllocEntry+AD (onecore\com\combase\coll\pgalloc.cxx, 637)
combase!CGIPTable::RegisterInterfaceInGlobalHlp+130 (onecore\com\combase\dcomrem\giptbl.cxx, 826)
combase!CGIPTable::RegisterInterfaceInGlobal+14 (onecore\com\combase\dcomrem\giptbl.cxx, 762)
windows.storage!CFreeThreadedItemContainer::Initialize+F3
windows.storage!CFSFolder::_BindToChild+347
windows.storage!CFSFolder::_Bind+A08
windows.storage!CFSFolder::BindToObject+40A
Windows.Storage.Search!CGrepQuery::_EvaluateItem+153
Windows.Storage.Search!CGrepQuery::CrawlForNextItemImpl+116
Windows.Storage.Search!TestHook_GrepQuery_CrawlForNextItem+1D
Windows.Storage.Search!CGrepQuery::CrawlForNextItem+1D
Windows.Storage.Search!CGrepRowset::GetRowsAt+59
Windows.Storage.Search!CQueryResultSet::FetchResultAt+E1
Windows.Storage.Search!CRowsetEnumeration::_EnumerateRowset+10F
Windows.Storage.Search!CRowsetEnumeration::WaitForResults+4D
Windows.Storage.Search!CQueryResultSet::_HandleBatches+7B
Windows.Storage.Search!CQueryResultSet::RealizeResults+252
windows.storage!CRealizeTask::_DoRealization+81
windows.storage!<lambda_a7b5b9f2e371967015d74b1e2c6d4552>::operator()+76
shcore!WorkThreadManager::CThread::ThreadProc+260
shcore!WorkThreadManager::CThread::s_ExecuteThreadProc+18
shcore!<lambda_142c425290ac4fbd4d5aee2fc3f7d711>::<lambda_invoker_cdecl>+23
ntdll!TppSimplepExecuteCallback+123
ntdll!TppWorkerThread+8D4
KERNEL32!BaseThreadInitThunk+14
ntdll!RtlUserThreadStart+21

  • 5a90 ( 5a90 - 0) 12 allocs BackTrace3733FFC6
  •  12 (    12 -     0) BackTrace3733FFC6 allocations    
    

ntdll!RtlpCallInterceptRoutine+3F
ntdll!RtlpAllocateHeapInternal+78B6B
windows.storage!operator new+12
windows.storage!CTopViewDescription_Create+3F
windows.storage!CFolderTypeDescription::_LoadTopViews+199
windows.storage!CFolderTypeDescription::_LoadFolderTypeInfo+2FA
windows.storage!CFolderTypeDescription::CFolderTypeInfoResourceGuard::v_LoadResource+61
windows.storage!CSRWLockResourceGuardBase::ExecuteReader<<lambda_c4ea1647e09c272de9f28c49495bae53> >+C2
windows.storage!CFolderTypeDescription::GetTopViewByID+56
windows.storage!SHGetTopViewDescription+68
windows.storage!CQueryOptions::_InitMembersFromTopViewInBroker+AA
windows.storage!Microsoft::WRL::Details::MakeAndInitialize<CQueryOptions,CQueryOptions,_GUID>+79
windows.storage!CStorageFolderStaticsBrokered::GetTopViewQueryOptions_Private+50
RPCRT4!Invoke+73
RPCRT4!Ndr64StubWorker+B56
RPCRT4!NdrStubCall3+C9
combase!CStdStubBuffer_Invoke+5F (onecore\com\combase\ndr\ndrole\stub.cxx, 1524)
RPCRT4!CStdStubBuffer_Invoke+3B
combase!ObjectMethodExceptionHandlingAction<<lambda_c9f3956a20c9da92a64affc24fdd69ec> >+43 (onecore\com\combase\dcomrem\excepn.hxx, 87)
combase!DefaultStubInvoke+1C3 (onecore\com\combase\dcomrem\channelb.cxx, 1452)
combase!SyncServerCall::StubInvoke+26 (onecore\com\combase\dcomrem\servercall.hpp, 826)
combase!ServerCall::ContextInvoke+42A (onecore\com\combase\dcomrem\ctxchnl.cxx, 1418)
combase!ReentrantSTAInvokeInApartment+19D (onecore\com\combase\dcomrem\reentrantsta.cpp, 112)
combase!AppInvoke+1EC (onecore\com\combase\dcomrem\channelb.cxx, 1182)
combase!ComInvokeWithLockAndIPID+681 (onecore\com\combase\dcomrem\channelb.cxx, 2290)
combase!ThreadWndProc+3AD (onecore\com\combase\dcomrem\chancont.cxx, 744)
USER32!UserCallWinProcCheckWow+2BD
USER32!DispatchMessageWorker+1E2
shcore!WorkThreadManager::CThread::ThreadProc+8CC
shcore!WorkThreadManager::CThread::s_ExecuteThreadProc+18
shcore!<lambda_9844335fc14345151eefcc3593dd6895>::<lambda_invoker_cdecl>+11
KERNEL32!BaseThreadInitThunk+14

  • 3c80 ( 3c80 - 0) 8 allocs BackTrace34EFBA86
  •   8 (     8 -     0) BackTrace34EFBA86 allocations    
    

ntdll!RtlpCallInterceptRoutine+3F
ntdll!RtlpAllocateHeapInternal+78B6B
ucrtbase!_calloc_base+4E
ucrtbase!DllMainDispatch+125
ntdll!LdrpCallInitRoutine+65
ntdll!LdrpInitializeThread+15A
ntdll!_LdrpInitialize+89
ntdll!LdrpInitialize+3B
ntdll!LdrInitializeThunk+E

  • 3842 ( 3842 - 0) 12 allocs BackTrace37342006
  •  12 (    12 -     0) BackTrace37342006 allocations    
    

ntdll!RtlpCallInterceptRoutine+3F
ntdll!RtlpAllocateHeapInternal+78B6B
shcore!SHStrDupW+4B
propsys!PSPropertyBag_ReadStrAlloc+2F
windows.storage!CTopViewDescription::Initialize+2AB
windows.storage!CTopViewDescription_Create+68
windows.storage!CFolderTypeDescription::_LoadTopViews+199
windows.storage!CFolderTypeDescription::_LoadFolderTypeInfo+2FA
windows.storage!CFolderTypeDescription::CFolderTypeInfoResourceGuard::v_LoadResource+61
windows.storage!CSRWLockResourceGuardBase::ExecuteReader<<lambda_c4ea1647e09c272de9f28c49495bae53> >+C2
windows.storage!CFolderTypeDescription::GetTopViewByID+56
windows.storage!SHGetTopViewDescription+68
windows.storage!CQueryOptions::_InitMembersFromTopViewInBroker+AA
windows.storage!Microsoft::WRL::Details::MakeAndInitialize<CQueryOptions,CQueryOptions,_GUID>+79
windows.storage!CStorageFolderStaticsBrokered::GetTopViewQueryOptions_Private+50
RPCRT4!Invoke+73
RPCRT4!Ndr64StubWorker+B56
RPCRT4!NdrStubCall3+C9
combase!CStdStubBuffer_Invoke+5F (onecore\com\combase\ndr\ndrole\stub.cxx, 1524)
RPCRT4!CStdStubBuffer_Invoke+3B
combase!ObjectMethodExceptionHandlingAction<<lambda_c9f3956a20c9da92a64affc24fdd69ec> >+43 (onecore\com\combase\dcomrem\excepn.hxx, 87)
combase!DefaultStubInvoke+1C3 (onecore\com\combase\dcomrem\channelb.cxx, 1452)
combase!SyncServerCall::StubInvoke+26 (onecore\com\combase\dcomrem\servercall.hpp, 826)
combase!ServerCall::ContextInvoke+42A (onecore\com\combase\dcomrem\ctxchnl.cxx, 1418)
combase!ReentrantSTAInvokeInApartment+19D (onecore\com\combase\dcomrem\reentrantsta.cpp, 112)
combase!AppInvoke+1EC (onecore\com\combase\dcomrem\channelb.cxx, 1182)
combase!ComInvokeWithLockAndIPID+681 (onecore\com\combase\dcomrem\channelb.cxx, 2290)
combase!ThreadWndProc+3AD (onecore\com\combase\dcomrem\chancont.cxx, 744)
USER32!UserCallWinProcCheckWow+2BD
USER32!DispatchMessageWorker+1E2
shcore!WorkThreadManager::CThread::ThreadProc+8CC
shcore!WorkThreadManager::CThread::s_ExecuteThreadProc+18

  • 2f4e ( 2f4e - 0) 78 allocs BackTrace37757A46
  •  78 (    78 -     0) BackTrace37757A46 allocations    
    

ntdll!RtlpCallInterceptRoutine+3F
ntdll!RtlpAllocateHeapInternal+78B6B
KERNELBASE!LocalAlloc+6D
windows.storage!CByteHashTable::_AddUpdateItem+E9
windows.storage!_LookupForSet+BE
windows.storage!_SetFileClassInt+40
windows.storage!CFileExtension::EnsureClassFlags+20F
windows.storage!CFileSysItemString::GetJunctionClsid+7C
windows.storage!CFSFolder::_ItemHasNavigationEnum+4C
windows.storage!CFSFolder::_CreateIDList+839
windows.storage!CFileSysEnum::CreateIDList+62
windows.storage!CFileSysEnum::Next+102
Windows.Storage.Search!CGrepQuery::CrawlForNextItemImpl+A7
Windows.Storage.Search!TestHook_GrepQuery_CrawlForNextItem+1D
Windows.Storage.Search!CGrepQuery::CrawlForNextItem+1D
Windows.Storage.Search!CGrepRowset::GetRowsAt+59
Windows.Storage.Search!CQueryResultSet::FetchResultAt+E1
Windows.Storage.Search!CRowsetEnumeration::_EnumerateRowset+10F
Windows.Storage.Search!CRowsetEnumeration::WaitForResults+4D
Windows.Storage.Search!CQueryResultSet::_HandleBatches+7B
Windows.Storage.Search!CQueryResultSet::RealizeResults+252
windows.storage!CRealizeTask::_DoRealization+81
windows.storage!<lambda_a7b5b9f2e371967015d74b1e2c6d4552>::operator()+76
shcore!WorkThreadManager::CThread::ThreadProc+260
shcore!WorkThreadManager::CThread::s_ExecuteThreadProc+18
shcore!<lambda_142c425290ac4fbd4d5aee2fc3f7d711>::<lambda_invoker_cdecl>+23
ntdll!TppSimplepExecuteCallback+123
ntdll!TppWorkerThread+8D4
KERNEL32!BaseThreadInitThunk+14
ntdll!RtlUserThreadStart+21

Universal Windows Platform (UWP)
{count} votes