Как заставить процесс .NET исчерпать память, не исчерпывая всю системную память - PullRequest
6 голосов
/ 07 мая 2009

Проблема проста, у меня есть процесс, который делает ETL для некоторых XML-файлов. Мы начали получать действительно большие XML-файлы, а я начал получать исключения OutOfMemoryExceptions.

Исправить процесс относительно просто. Тем не менее, я хотел бы провести модульное тестирование для моего набора NUnit, чтобы убедиться, что процесс будет по-прежнему способен обрабатывать действительно большие файлы. Однако на самом деле нехватка памяти на моей рабочей станции замедляет работу компьютера и отнимает много времени. Хранение огромного тестового файла в системе контроля версий также является плохой идеей. Если бы я мог искусственно ограничить процесс, поток или домен приложения только фиксированным количеством оперативной памяти, скажем, 128 мегабайт, я мог бы провести меньший модульный тест, который бы не поставил мою рабочую станцию ​​на колени.

Есть предложения? Это какой-то неуправляемый API я могу P / Invoke?

Ответы [ 4 ]

2 голосов
/ 07 мая 2009

Разве вы не можете использовать фальшивый фреймворк для выделения памяти, чтобы он выдавал OutOfMemoryException в качестве одного из тестов?

Сказав, что, хотя, если вы действительно исчерпали память, ваше приложение не может ничего сделать безопасно, но если вы можете, по крайней мере, изящно потерпеть неудачу, ваши пользователи будут благодарны.

Пример: У меня был случай на предыдущей работе, где мы отображали 3D модели заводов в режиме реального времени. Модели стали настолько большими, что при попытке загрузить текстуры у нас возникали сбои памяти. Нам удалось сохранить работоспособность приложения и рендеринг, убедившись, что код справился с нулевыми указателями, хотя остальная часть кода считала, что там должна быть информация о текстуре.

1 голос
/ 08 мая 2009

Лучше всего издеваться. На самом деле повышение ООМ по определению не является модульным тестом. Имея дело с памятью, вы имеете дело с нагрузочным тестированием. Если вы прочтете ссылки внизу этого письма, то обнаружите, что настоящие OOM чрезвычайно трудно воспроизвести и отладить в лучшем случае. Придуманное исключение OOM не является истинной причиной исключения и, следовательно, не более интересно, чем имитация для тестирования.

Придерживайтесь модульного теста, используя макет для проверки. Если вы по-прежнему получаете OOM, выделите больше памяти на вашем сервере и сделайте процесс перезапускать / перезапускать чаще.

Вот несколько интересных чтений об исключениях OutMemory, которые я собрал в последний раз, когда сражался с ними. Сводка: OOM возникают, когда система не может выделить запрошенную вами сумму, что не означает, что у вас недостаточно памяти.

0 голосов
/ 08 мая 2009

Довольно просто вызывать исключения из памяти в процессе.

Просто создайте цикл, который выделяет память в блоках, которые достаточно малы, чтобы не помещаться в кучу больших объектов (но не слишком много, что у вас есть, что вызывает исключение), а затем вы можете попытаться открыть меньший файл, и приведет к тому, что открытие файла не сможет выделить достаточно непрерывной памяти, и вы получите исключение OOM при открытии файла, не требуя огромного файла. Как то так ...

List<byte[]> items = new List<byte[]>();
for (int i = 0; i < 10000; i++)
{
     byte[] c = new byte[160000];
     items.Add(c);
}

byte[] next = new byte[1000000000];

Если вы запустите приведенный выше код как есть, вы получите исключение OOM в последней строке. Но если вы сначала закомментируете цикл, он будет выполнен без ошибок. Вам, вероятно, придется немного подправить цикл, чтобы каждый раз вызывать ошибку при открытии файла, но вы можете это сделать. Просто запустите цикл перед вызовом, чтобы открыть файл в тесте, и вы израсходовали большой кусок памяти, и ваше открытие должно завершиться неудачей.

Кроме того, вы можете посмотреть настройку параметра / 3GB, если это вариант для вас. Это не всегда правильный ответ, и с ним связаны недостатки, но он изменяет форму разделения виртуальной памяти с 2 ГБ / 2 ГБ на 1 ГБ / 3 ГБ, предоставляя вашему процессу доступ к большему виртуальному адресному пространству. Это даст вам немного больше места для файлов, которые вы можете открыть. Опять же, вы должны прочитать о недостатках этого, прежде чем использовать его в качестве решения, и убедиться, что оно того стоит, если это поможет вашей ситуации.

Здесь , как включить его на сервере

0 голосов
/ 07 мая 2009

Я не совсем понимаю, что вы здесь делаете. Давайте предположим, что каким-то образом вы создали искусственно маленькую «тестовую среду», которая не могла выделить большие фрагменты памяти, поэтому она вызвала исключения OutOfMemoryException для небольших файлов. Что вы приобрели? Модульный тест должен был проверить, можете ли вы обрабатывать большие файлы в реальной системе, верно?

Важным предположением является то, что вы можете обрабатывать файлы "такими большими, какими они должны быть" в любой системе, на которой они будут работать, и нет никакого реального способа провести модульное тестирование, кроме как проверить этот файл на эта система.

(Меньшая, менее важная вещь может заключаться в том, правильно ли вы обрабатываете OutOfMemoryException s, но вам не нужно фактически исчерпывать память, чтобы проверить это; просто заставьте ваш метод вызывать исключение время от времени и наблюдайте что он делает правильно.)

...