Проблема не в потоке памяти. Проблема в Console.WriteLine
. намного быстрее записывать / читать материал в / из MemoryStream
, чем записывать в консоль, например. типичная конфигурация Windows. Возможно, вы обнуляете поток памяти каждый раз, когда читаете его, но как только вы очистили его, вы снимаете блокировку, и программа записи журнала начинает вращаться очень быстро .
В первой итерации предположим, что поток записи журнала имеет 5 мс для записи некоторых журналов. Чтобы записать это на консоль, потребуется больше , чем 5 мс, поэтому к тому времени, когда поток записи на консоль обойдется один раз, он будет иметь больше журналов на 5 мс займет больше времени, чем потребовалось для записи первых 5 мс журналов ... поэтому каждый раз, когда поток записи на консоль завершает запись предыдущего состояния журналов, он обнаруживает, что он имеет даже больше , и это занимает еще дольше , чтобы записать это: да, поток памяти занимал всю память, но это потому, что ему требовалась память для хранения всех журналов, пока поток записи на консоли был занят, потребляя последнюю загрузку.
Вот немного математики, просто для удовольствия:
d is rate at which logs are produced
c is how long it takes to consume a unit of logs
x(i) is the volume of logs produced during iteration i of the log-consumer
y(i) is how long it takes to consume the logs produced in iteration i
Мы можем написать несколько простых простых уравнений:
y(i) = c*x(i) (time to consume logs is a linear function of volume)
x(i+1) = d*y(i) (volume is a linear function of time between iterations)
Должно быть, мы можем определить, как объем журналов (пропорциональный использованию памяти) изменяется с каждой итерацией
x(i+1) = d*c*x(i)
Если d*c > 1
, то x
растет в геометрической прогрессии: плохо для использования памяти (хотя он все еще может расти только линейно во времени, потому что d
является ограничивающим фактором (напомним, что мы смотрим на затраты на одну итерацию, а не на время) ))
Если мы рассмотрим 1/c
(скорость потребления журналов), то ясно, что это условие выполняется, когда
d > 1/c (i.e. rate at which logs are produced is greater than the rate at which logs are consumed)
Запись в поток памяти дешевле, чем запись в консоль: d > 1/c
, поэтому у нас есть фундаментальная проблема, которую не решит никакая хитрость: вы не можете написать такой объем логи на консоль.
Вы можете увидеть эту проблему с выходом, потому что отметка времени не отслеживает время: она сразу же отстает. Удаление Console.WriteLine
оставляет приложение на моем компьютере около 10 МБ. Вы также можете увидеть проблему в использовании памяти: время от времени она переходит, что является (нечастым) событием программы записи консоли, запускающей новую итерацию и копирующей весь поток (byte[]
) в char[]
( ReadToEnd
) и, наконец, получается string
: не имеет значения, что byte[]
может быть немедленно освобождено, потому что у вас есть 2 объекта одинакового размера, чтобы восполнить слабину.
<ч />
Кстати, использование SetLength(0)
только запутает проблему, создав больше байтовых массивов, и, возможно, фактически увеличит пиковое использование памяти, потому что это не уменьшает максимальную емкость потока памяти и означает, что есть выброшенные предметы лежат в ожидании сбора мусора.
<ч />
Как уже говорилось в комментариях, вам не следует обращаться к монитору между потоками; использование await
означает, что контекст будет сохранен при возврате элемента управления методу записи журнала, но нет гарантии, что вы получите тот же поток.