Windows Phone 上的内存消耗开销

Memory consumption overhead on Windows Phone

通用Windows 8.1 在此处存储项目。

我正在使用 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 个阅读线程时:

那里发生了什么?我只是做错了什么吗?

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

// 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);
}

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

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

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