【问题标题】:Memory consumption overhead on Windows PhoneWindows Phone 上的内存消耗开销
【发布时间】:2016-05-04 11:04:50
【问题描述】:

Universal Windows 8.1 Store 项目在这里。

我正在使用 512mb 内存的模拟器上进行一些内存分析。我在这里谈论的测试并不完全实用,我只是想了解一下机制。

测试项目非常简单:它打开一个大文件(超过 700mb)用于在线程上顺序读取,并通过 15mb 缓冲区读取它,在每次迭代后执行await Task.Delay();,以保持线程运行更长时间。我用Task.Run() 多次启动相同的代码并观察内存消耗。

当我强制 GC 时,内存量接近我的预期:

some initial 6-7 mb + 
number_of_tasks * buffer_size + 
some little memory per task for the objects created by the reading method

但让我感到困惑的是当我开始执行任务时的初始内存开销。在触发 GC 之前,应用程序消耗了两倍的内存,因此我只有 6 个同时读取线程出现内存不足异常。

例如,当我有 5 个阅读线程时:

  • 应用以~6.5mb的内存开头,
  • 然后在创建任务时增加到~175mb为什么?
  • 拍摄快照时(触发 GC),消耗量降至~85mb
  • 当所有线程完成读取时,内存下降到~10mb

那里会发生什么?我是不是做错了什么?

这是我用于测试的代码的简短版本:

// the code is placed in the only page of the default Universal App -> Blank App template
protected override void OnNavigatedTo(NavigationEventArgs e)
{
  Test();
}

async Task Test()
{
    Debug.WriteLine("BEGIN");
    var task1 = Task.Run(()=>ReadFile("1"));
    var task2 = Task.Run(()=>ReadFile("2"));
    var task3 = Task.Run(()=>ReadFile("3"));
    var task4 = Task.Run(()=>ReadFile("4"));
    var task5 = Task.Run(()=>ReadFile("5"));
    Debug.WriteLine("END");

    await Task.WhenAll(task1, task2, task3, task4, task5, task6);

    Debug.WriteLine("ALL TASKS COMPLETE");
}

async Task ReadFile(string tag)
{
    Debug.WriteLine("FILE {0}: begin", tag);
    var file = await StorageFile.GetFileFromApplicationUriAsync(
        new Uri("ms-appx:///Assets/test.rar")
    );      
    using(var seqStream = await file.OpenSequentialReadAsync()) {
        var buf = CryptographicBuffer.CreateFromByteArray(new byte[15*1024*1024]);
        IBuffer result = null;
        uint total = 0;
        do {
            Debug.WriteLine("FILE {0}: read {1} bytes", tag, buf.Length);
            var operation = seqStream.ReadAsync(buf, buf.Capacity, InputStreamOptions.None);
            await operation;
            if (operation.Status == AsyncStatus.Completed) {
                result = operation.GetResults();
                total += result.Length;
                Debug.WriteLine("FILE {0}: got {1} bytes", tag, total);
            } else {
                result = null;
            }
            await Task.Delay(234);
        } while (result != null && result.Length == buf.Capacity);
    }
    Debug.WriteLine("FILE {0}: end", tag);
}

更新:我发现,当我不使用线程池而只使用var task1 = ReadFile("1"); 时,内存开销会降低 5 倍(尽管它仍然存在)。为什么? (在实际项目中,我对文件内容进行了一些 cpu-bound 工作,而不仅仅是异步 IO,所以我想无论如何我都需要单独的线程。)

【问题讨论】:

    标签: c# memory-management windows-runtime windows-phone-8.1 win-universal-app


    【解决方案1】:

    问题出在 CryptographicBuffer 中。 Windows.Storage.Streams.Buffer 应该用于文件 IO。

    var buf = new Windows.Storage.Streams.Buffer(16*1024); 
    

    【讨论】:

    • 谢谢!不幸的是,这并没有回答我的问题。
    • 减少缓冲区大小后,应用程序消耗的内存是否超过 20-30mb?
    • 它没有。问题是:为什么?我在没有线程池的情况下获得了更好的结果,并且缓冲区很小,我根本没有太多开销。为什么会这样?
    • 我最初选择大缓冲区只是为了能够看到少量并发读取的影响。
    • 唯一的问题是在一个巨大的缓冲区(15mb)中。为每个文件/任务创建 15 mb 缓冲区,并在任务完成时由 GC 收集。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-30
    • 1970-01-01
    • 1970-01-01
    • 2010-10-12
    • 1970-01-01
    • 2010-09-26
    相关资源
    最近更新 更多