通用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个阅读线程时:
~6.5mb
内存开头,~175mb
(为什么?)~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);
}
UPDATE :我发现,当我不使用线程池而只执行var task1 = ReadFile("1");
时,内存开销会降低约5倍(尽管它仍然存在)。为什么? (在实际项目中,我对文件内容有一些cpu绑定的工作,而不仅仅是异步IO,所以我想我还是需要单独的线程。)
答案 0 :(得分:2)
问题在于CryptographicBuffer。 Windows.Storage.Streams.Buffer应该用于文件IO。
var buf = new Windows.Storage.Streams.Buffer(16*1024);