Я разрабатываю решение С#, UWP 10, которое общается с сетевым устройством, используя быстрый, непрерывный цикл чтения/записи. StreamSocket, предлагаемый API, по-видимому, отлично работает, пока я не понял, что произошла утечка памяти: в куче есть накопление Task<uint32>
в порядке сотен в минуту.
Я использую простой старинный цикл while (true)
внутри async Task
или используя самостоятельную проводку ActionBlock<T>
с потоком данных TPL (в соответствии с этим ответом), результат тот же.
Я могу еще больше изолировать проблему, если я удалю чтение из сокета и сосредоточусь на написании:
Использую ли я подход DataWriter.StoreAsync
или более прямой StreamSocket.OutputStream.WriteAsync(IBuffer buffer)
, проблема остается. Кроме того, добавление к нему .AsTask()
не имеет значения.
Даже когда сборщик мусора работает, эти Task<uint32>
никогда не удаляются из кучи. Все эти задачи полны (RanToCompletion
), не имеют ошибок или какого-либо другого значения свойства, которое указывает на "не совсем готовый к возврату".
Кажется, у меня есть проблема с эта страница (массив байтов, идущий из управляемого в неуправляемый мир, предотвращает выпуск памяти), но предписанное решение кажется довольно резким: единственный способ обойти это - написать всю логику связи в С++/CX. Надеюсь, это неправда; конечно, другие разработчики С# успешно реализовали непрерывные высокоскоростные сетевые коммуникации без утечек памяти. И, конечно же, Microsoft не выпустит API, который работает без утечек памяти в С++/CX
ИЗМЕНИТЬ
В соответствии с запросом, некоторый пример кода. В моем собственном коде слишком много слоев, но гораздо более простой пример можно наблюдать с этот образец Microsoft. Я сделал простую модификацию, чтобы отправить 1000 раз в цикле, чтобы выделить проблему. Это соответствующий код:
public sealed partial class Scenario3 : Page
{
// some code omitted
private async void SendHello_Click(object sender, RoutedEventArgs e)
{
// some code omitted
StreamSocket socket = //get global object; socket is already connected
DataWriter writer = new DataWriter(socket.OutputStream);
for (int i = 0; i < 1000; i++)
{
string stringToSend = "Hello";
writer.WriteUInt32(writer.MeasureString(stringToSend));
writer.WriteString(stringToSend);
await writer.StoreAsync();
}
}
}
При запуске приложения и подключении сокета в куче есть только экземпляр Task<uint32>
. После нажатия кнопки "SendHello" имеется 86 экземпляров. После нажатия 2 раза: 129 экземпляров.
Изменить # 2 После запуска моего приложения (с плотным циклом отправки/получения) в течение 3 часов я вижу, что определенная проблема: 0,5 миллиона экземпляров Task, которые никогда не получат GC'd, а память приложений увеличилась с начального 46 МБ до 105 МБ. Очевидно, что это приложение не может работать неопределенно. Однако... это относится только к запуску в режиме отладки. Если я скомпилирую свое приложение в режиме выпуска, разверните его и запустите, проблем с памятью не будет. Я могу оставить его работать всю ночь, и ясно, что память управляется должным образом. Дело закрыто.