Как вернуть неиспользованную память из кучи больших объектов LOH из нескольких управляемых приложений? - PullRequest
8 голосов
/ 24 июня 2009

Во время разговора с коллегой о конкретной группе приложений, использующих почти 1,5 ГБ памяти при запуске ... он указал мне на очень хорошую ссылку на .NET отладку продукции

То, что меня озадачило, это ...

Например, если вы выделите 1 МБ память на один блок, большой Размер кучи объекта увеличивается до 1 МБ. Когда вы освобождаете этот объект, большой куча объектов не разрушает виртуальная память, поэтому куча остается на 1 МБ в размере. Если вы выделите другой 500-килобайтный блок позже, новый блок выделяется в пределах 1 МБ блока память, принадлежащая большому объекту куча. В течение срока службы процесса куча больших объектов всегда растет все большие выделения блоков в настоящее время упоминается, но никогда сжимается, когда объекты выпущены, даже если происходит сборка мусора. Рисунок 2.4 на следующей странице показывает пример кучи большого объекта.

Теперь, допустим, у нас есть вымышленное приложение, которое создает поток больших объектов (> 85 КБ), поэтому объем кучи больших объектов увеличивается, скажем, до 200 Мег. Теперь допустим, что у нас запущено 10 таких экземпляров приложения, так что выделено 2000 мегабайт. Теперь эта память никогда не возвращается ОС, пока процесс не завершится ... (это я понял)

Есть ли пробелы в моем понимании? Как нам вернуть неиспользованную память в различных LOHeaps; мы не создаем идеальный шторм OutOfMemoryExceptions?

Обновление: Из ответа Марка я хотел уточнить, что на объекты LOH не ссылаются - большие объекты используют use-n-throw - однако куча не уменьшается, хотя куча относительно пустой пост начального всплеска.

Обновление № 2: Просто включил фрагмент кода (преувеличено, но я думаю, что это понятно). Я вижу исключение OutOfMemoryException примерно в то время, когда виртуальная память достигает отметки 1,5G на моей машине (1,7 G на другом) .. Из в блоге Эрика Л. , «память процесса может быть визуализирована как массивный файл на диске ...» - этот результат, таким образом, является неожиданным. У машин в этом случае было ГБ свободного места на жестком диске. Налагает ли файл ОС PageFile.sys (или связанные с ним настройки) какие-либо ограничения?

        static float _megaBytes;
        static readonly int BYTES_IN_MB = 1024*1024;

        static void BigBite()
        {
           try
           {
              var list = new List<byte[]>();
              int i = 1;

              for (int x = 0; x < 1500; x++)
              {
                 var memory = new byte[BYTES_IN_MB + i];
                 _megaBytes += memory.Length / BYTES_IN_MB;
                 list.Add(memory);
                 Console.WriteLine("Allocation #{0} : {1}MB now", i++, _megaBytes);
              }
           }
           catch (Exception e)
           {  Console.WriteLine("Boom! {0}", e); // I put a breakpoint here to check the console
              throw;
           }
        }
       static void Main(string[] args)
        {
            BigBite();
            Console.WriteLine("Check VM now!"); Console.ReadLine();
            _megaBytes = 0;

            ThreadPool.QueueUserWorkItem(delegate { BigBite(); });
            ThreadPool.QueueUserWorkItem(delegate { BigBite(); });
            Console.ReadLine();   // will blow before it reaches here
        }

Ответы [ 3 ]

5 голосов
/ 25 июня 2009

Есть пояснение, которое я хотел бы сделать первым. - При условии, что вы используете приложение как 32-битное приложение, пространство виртуальной машины, доступное для вашего процесса, составляет всего 2 ГБ, 3 ГБ, если вы включили переключатель большого адресного пространства, поэтому даже если у вас есть ОГРОМНЫЙ файл подкачки, не имеет значения, если вы 32-битный процесс, имеет значение, если вы запускаете 64-битную, где у вас огромное адресное пространство.

  • Объект с размером> 85000 байт размещен на LOH, обратите внимание, что это 85000 байт , а не 85K, это также детали реализации, которые могут измениться. Теперь вернемся к вашему вопросу. GC разблокирует сегменты LOH, которые не используются в 2 ситуациях 1- Когда давление памяти на машине высокое (~ 95-98%) 2- Когда он не сможет удовлетворить новые запросы на выделение ресурсов, он выведет из употребления неиспользуемые страницы в LOH

так что вы вернете память в одном из этих случаев. Тот факт, что вы нажимаете OOM до достижения предела в 2 ГБ, может означать, что у вас есть фрагментация VA, фрагментация VA происходит, когда у вас нет непрерывного адресного пространства VA для удовлетворения нового выделения, например, вы просите сегмент 8 КБ, и вы не в вашем VA должно быть 2 последовательных страницы (при условии, что размер страницы равен 4 КБ)

вы можете использовать расширение! Vamap в средствах отладки для окон для проверки этого.

Надеюсь, это поможет Спасибо

3 голосов
/ 24 июня 2009

Если LOH хочет сохранить память, это зависит от LOH - однако, не забывайте, что OutOfMemoryException для каждого процесса, так как действительно жесткий диск является ограничивающим фактором для виртуальной памяти. Об этом недавно написал Эрик Липперт . Конечно, это не мешает работе всех страниц подкачки ...

2 голосов
/ 24 июня 2009

Что ж, если у вас действительно есть такой тип распределения, вы можете переместить свои большие объекты в другой домен приложения - когда вы решите освободить все большие объекты, освободите домен приложения, и куча для этого домена приложения будет освобождена.

...