Довольно долго мы боролись за производительность программы WinDraw, а именно за взаимодействие между WinDraw и MS SQL Server.
За время этой борьбы мы сделали несколько серьезных выводов:
1. Использование метода dbo.ZipUnPack в запросах(то есть на стороне SQL Server) построителя отчетов Stimulsoft Reports.Net приводил к тому, что ошибка System.OutOfMemoryException появлялась гораздо чаще. Переведя выполнение этого метода на сторону сервера приложений (т.е. используя Atechnology.Components.ZipArchiver.UnZip2 (byte[] classnative) ) мы значительно увеличили время работы SQLServer без перезагрузки.
2. Железный апгрейд не решает проблему System.OutOfMemoryException, доказано опытным путем. А именно, с момента первого описания проблемы (Проблема производительности WinDraw. ) мы приобрели новый сервер — Hewlett Packard Proliant DL380G6 (2xXeonQC, 32Gb оперативной памяти), на котором установили Microsoft Windows Server 2003 Ent, Microsoft SQL Server 2008 Ent. В настройках Microsoft SQL Server включили опцию Address Windowing Extensions (AWE). Уже на следующий день мы получили ошибку System.OutOfMemoryException, причем судя по Task Manager оперативная память была использована всего НАПОЛОВИНУ.
Устраняем ошибку «На компьютере недостаточно памяти»
Исходя из всего этого, и множества советов в интернете(правда большинство советов относилось к работе программы 1С с SQL Server, но проблема была очень похожа на нашу) — решено было попробовать использовать x64 платформу и ПО.
На Этот же самый сервер (Hewlett Packard Proliant DL380G6 (2xXeonQC, 32Gb оперативной памяти)) была установлена операционная система Microsoft Windows Server 2008 R2 Enterprise x64, Microsoft SQL Server 2008 R2 x64, опция Address Windowing Extensions (AWE) выключена (кстати пришла идея попробовать включить и ее. ). Итог потрясающий.
Уже больше месяца мы не получали ошибки System.OutOfMemoryException, хотя оперативная память используется практически полностью!
Исходя из этого данный набор ПО считаем необходимым при одновременном доступе к SQL Server более 30 пользователей.
З.Ы. В ближайшее время попробуем включить опцию Address Windowing Extensions (AWE) и опишем результат!
Немного технической информации!
Механизм Address Windowing Extensions (AWE), используемый в SQL Server, состоит из двух частей, распределяющих физическую память и отображающую её на Virtual Address Space (VAS) данного процесса. Если физическая память распределена, то операционная система уже не сможет её затребовать, пока использующий её процесс не будет завершён или этот процесс освободит память, вернув её операционной системе. Приложение может управлять и даже полностью предотвращать листание. Преимущество механизма mapping/unmapping в том, что одна и та же физическая страница может быть отображена на разные участки VAS. На 64-х битных платформах в unmapping нет необходимости, поскольку VAS мы имеем достаточно, чтобы вместить всю имеющуюся физическую память.
🔧В СИСТЕМЕ НЕДОСТАТОЧНО ПАМЯТИ, ВЫЛЕТАЕТ ИЗ ИГРЫ / [2022]
Из теории операционных систем, для описания отображения страницы VAS на физические страницы, система оперирует записями таблицы страниц — Page Table Entry (PTE). Внутри физическая страница описывается номером блока страниц — Page Frame Number (PFN). Из PFN можно получить всю информацию о физической странице, которую он представляет.
Например, PFN показывает, какому Non-Uniform Memory Access (NUMA) — узлу принадлежит эта страница. В операционной системе есть база данных, хранящая совокупность PFN, которыми система управляет. Если страница в VAS является закреплённой, существует PTE, который может указывать или не указывать на задействованные PFN.
Концептуально, страница, которую представляет PTE, может быть в памяти или нет, например, если она выгружена на диск. В первом случае она привязана к задействованному PFN, а в последнем — нет. В свою очередь, как только физическая страница привязывается к странице в VAS, её PFN возвращаются PTE.
Когда операционная система закрепляет, освобождает, получает/отдаёт страницы задействованного PTE, или должна получить немного информации об этом (например аллокация NUMA), она должно задействовать блокировку рабочего множества процесса — чтобы обеспечить стабильность привязки PTE к PFN. Эта блокировка обходиться довольно дорого и может испортить масштабируемость процесса.
При распределении физических страниц, использование AWE механизма предоставляет нам набор записей PFN непосредственно из базы данных PFN. Операционная система обязана устанавливать блокировку на базу данных PFN во время распределения записей PFN. Используя механизм отображения AWE, Вы можете отобразить аллоцируемые записи PFN на VAS процесса.
Когда происходит такое отображение, PTE аллоцируются, привязываются к PFN и отмечаются как блокированые. В этом случае операционная система должна разово установить блокировку рабочего множество процесса. При отображении обычных страниц, операционная система делает это по требованию и, следовательно, должна будет заполучить рабочее множество и установить блокировку в базе данных PFN для каждой страницы. Так как страницы в памяти блокированы, в момент листания эти PTE системой будет игнорироваться.
На 64-х битных платформах лучше называть такие страницы блокированными страницами (locked pages), и, пожалуйста, не путайте их со страницами, блокированными средствами VirtualLock API. Как было описано выше, у блокированных страниц есть два важных свойства — они не участвуют в листании, проводимом операционной системой, и во время распределения они захватывают рабочее множество и устанавливают разовую блокировку в базе данных для PFN.
Первое свойство имеет не очевидное влияние на высокопроизводительные системы, такие, как системы с архитектурой NUMA. Оно приводит к явной резидентности в памяти. Помните, что система закрепляет страницы по требованию. Для распределения физической памяти будет использоваться узел, на котором выполняется обращающийся к памяти поток.
Только после этого страница может быть выгружена операционной системой во время свопинга. Далее, она может снова попасть в память, операционная система снова распределит физическую страницу узлу, на котором поток продолжает работать с этой памятью. В этом случае узел может оказаться уже совсем другим. Такое поведение приведет к дополнительной нагрузке на приложения, которые используют для страниц резидентность NUMA. Блокировка страницы позволяет разрешить эту проблему, полностью защищая их от листания.
Второе свойство — захват рабочего множества и блокировка в базе данных только PFN, дает возможность приложениям работать быстрее и повышает масштабируемость пилообразной нагрузки.
В NUMA архитектуре, SQL Server Buffer Pool фиксирует каждую распределенную страницу с выделенным для неё узлом. Достигается этого за счёт использования QueryWorkingSetEx. Как только страница распределена, вызывается этот API, который позволяет узнать детали резидентности страницы. Делается это только один раз.
Поэтому включение locked pages для SQL Server на 64-х битной платформе улучшает работу с пилообразной нагрузкой и повышает производительность и масштабируемость на более длительных отрезках времени. При работе SQL Server в режиме locked pages, Вам не нужно больше волноваться о производительности системы в целом, зависимости от изъятия памяти у SQL Server, когда он участвует в механизме листания операционной системы, прослушивая оповещения отвечающего в системе за память API, и сокращая своё рабочее множество, когда это от него требуют.
Давайте подведём итог этой статьи: на 64-х битных платформах VAS мы имеем достаточно, чтобы вместить всю имеющуюся физическую память, поэтому вероятность получения исключения System.OutOfMemoryException практически исключена.
Победа OutOfMemoryException : 6 комментариев
- Мимо Проходил 23 января 2011 «. такие, какими их написал разработчик. . » Ой! я извиняюсь, я думал вы и есть разработчик. Разработчики не соображают ничего в MS SQL SERVER’е потому у вас как заказчика такие проблемы. Очень жаль.
- Внедренец Автор записи 24 января 2011 Нет, мы заказчики. Хотя понемногу становимся разработчиками Ибо разработчик не спешит решать проблем. Кстати, недавно появилось обновление для MS SQL 2008 R2, которое борется с сетевой утечкой памяти. Обновление пока доступно только по требованию, мы его уже установили у себя, и пока тестируем. Но результаты уже впечатляют — память просто так не растет, как раньше. А постепенно набирается, по ночам понемногу возвращается. Как будем уверенны — опишу что это за обновление и как оно действует. Пока вот ссылка — support.microsoft.com/kb/2345451
Источник: www.gurin.ru
Сбои потока отрисовки WPF
В этом документе рассматриваются сбои в потоке отрисовки WPF с особым вниманием к тем, которые вызывают исключение в SyncFlush или NotifyPartitionIsZombie или вызывают зависание приложений в WaitForNextMessage или SynchronizeChannel .
Исходная версия продукта: платформа .NET Framework 4.8
Сбои в SyncFlush, WaitForNextMessage, SyncChannel и NotifyPartitionIsZombie
Разработчики часто сталкиваются с проблемами, связанными с отрисовкой потоков в приложениях Windows Presentation Foundation (WPF). Пользователи могут сообщать о том, что их приложение создает исключения, такие как:
- System.Runtime.InteropServices.COMException: UCEERR_RENDERTHREADFAILURE (исключение из HRESULT: 0x88980406)
- System.InvalidOperationException: в потоке отрисовки произошла не указанная ошибка.
- System.OutOfMemoryException: недостаточно памяти для продолжения выполнения программы.
Стек вызовов исключения начинается с или SyncFlush NotifyPartitionIsZombie . Например:
at System.Windows.Media.Composition.DUCE.Channel.SyncFlush() at System.Windows.Interop.HwndTarget.UpdateWindowSettings(Boolean enableRenderTarget, Nullable`1 channelSet) at System.Windows.Interop.HwndTarget.UpdateWindowSettings(Boolean enableRenderTarget) at System.Windows.Interop.HwndTarget.UpdateWindowPos(IntPtr lParam) at System.Windows.Interop.HwndTarget.HandleMessage(WindowMessage msg, IntPtr wparam, IntPtr lparam)
at System.Windows.Media.MediaContext.NotifyPartitionIsZombie(Int32 failureCode) at System.Windows.Media.MediaContext.NotifyChannelMessage() at System.Windows.Interop.HwndTarget.HandleMessage(Int32 msg, IntPtr wparam, IntPtr lparam)
Приложение также может зависнуть в WaitForNextMessage или SynchronizeChannel с таким стеком вызовов, как:
ntdll.dll!NtWaitForMultipleObjects kernelbase.dll!WaitForMultipleObjectsEx kernelbase.dll!WaitForMultipleObjects wpfgfx_v0400.dll!CMilChannel::WaitForNextMessage wpfgfx_v0400.dll!MilComposition_WaitForNextMessage presentationcore.dll!System.Windows.Media.MediaContext.CompleteRender
kernelbase.dll!WaitForSingleObject wpfgfx_v0400.dll!CMilConnection::SynchronizeChannel wpfgfx_v0400.dll!CMilChannel::SyncFlush presentationcore.dll!System.Windows.Media.Composition.DUCE+Channel.SyncFlush presentationcore.dll!System.Windows.Media.MediaContext.CompleteRender presentationcore.dll!System.Windows.Interop.HwndTarget.OnResize presentationcore.dll!System.Windows.Interop.HwndTarget.HandleMessage
Это симптомы сбоя в потоке отрисовки. Это сложная проблема для диагностики, так как полученные исключения и стеки вызовов являются универсальными. Сбои потока отрисовки создают один из приведенных выше стеков вызовов (или незначительные их варианты), независимо от первопричины. Это делает диагностику проблемы или даже распознавание, когда два сбоя или зависания связаны с одной и той же первопричиной, особенно трудно.
Описание потока отрисовки WPF и его отличия от потока пользовательского интерфейса
Каждое приложение WPF может иметь один или несколько потоков пользовательского интерфейса с собственным насосом сообщений ( Dispatcher.Run ). Каждый поток пользовательского интерфейса отвечает за обработку оконных сообщений из очереди сообщений потока и их отправку в окна, принадлежащие тому потоку. Каждое приложение WPF имеет только один поток отрисовки. Это отдельный поток, который взаимодействует с DirectX/D3D (и (или) GDI, если используется конвейер отрисовки программного обеспечения. Для содержимого WPF каждый поток пользовательского интерфейса отправляет подробные инструкции потоку отрисовки о том, что нужно нарисовать. Затем поток отрисовки принимает эти инструкции и отрисовывает содержимое.
Причины сбоев, упомянутых выше
Упомянутые выше исключения и зависания возникают в потоке пользовательского интерфейса в результате того, что поток отрисовки WPF сталкивается с неустранимой ошибкой. Существует несколько возможных причин таких ошибок, но поток отрисовки не предоставляет эти сведения потоку пользовательского интерфейса. Так как эти исключения и зависания не связаны с одной корневой ошибкой или проблемой, нет конкретного способа их исправления.
Поток отрисовки WPF проверяет возвращаемое значение на успешное или неудачное выполнение при вызове другого компонента, например DirectX/D3D, User32 или GDI32. При обнаружении сбоя WPF «зомбитирует» секцию отрисовки и уведомляет поток пользовательского интерфейса о сбое при синхронизации двух потоков.
Поток отрисовки попытается сопоставить полученный сбой с соответствующим управляемым исключением. Например, если поток отрисовки WPF завершился сбоем из-за нехватки памяти, он сопоставляет сбой System.OutOfMemoryException с , и это будет исключение, отображаемое в потоке пользовательского интерфейса. Поток отрисовки синхронизируется только с потоком пользовательского интерфейса в нескольких местах, поэтому стеки вызовов выше обычно отображаются там, где вы заметили проблему, а не там, где она произошла. Чаще всего они синхронизируются в местах, где параметры окна обновляются (размер, положение и т. д.) или где поток пользовательского интерфейса обрабатывает сообщение канала из потока отрисовки.
По умолчанию исключения и стеки вызовов в потоке пользовательского интерфейса не помогают диагностировать проблему. Это связано с тем, что к моменту возникновения исключения поток отрисовки уже прошел точку сбоя. Критическое состояние потока отрисовки поможет понять, где и почему произошел сбой, но он уже потерян.
Это делает практически невозможным для пользователя, написав приложение WPF, узнать, почему произошел сбой или как его избежать. Для корпорации Майкрософт лишь немного лучше отлаживать это в посмертном файле дампа пользователя. Поток отрисовки сохраняет циклический буфер стека вызовов, который можно восстановить внутренне с помощью расширения отладчика и частных символов отладки, чтобы показать приблизительную начальную точку сбоя. Однако у нас нет доступа к критическому состоянию, такому как локальные, переменные стека и объекты кучи во время сбоя. Обычно мы снова запускаем приложение, чтобы найти сбои в вызовах, которые, как мы подозреваем, задействованы.
Распространенные причины сбоев
Наиболее распространенный сегмент сбоев потока отрисовки WPF связан с проблемами видеоустройства или драйвера. Когда WPF запрашивает у видеодрайвера возможности через DirectX, драйвер может неправильно отчеты о своих возможностях, что приводит к тому, что WPF принимает путь к коду, что приводит к некоторым сбоям DirectX/D3D.
Иногда драйвер не неправильно отображает свои возможности, но он был реализован неправильно. Большинство сбоев потока отрисовки вызваны попыткой WPF использовать конвейер отрисовки оборудования таким образом, чтобы выявить некоторые недостатки в драйвере. Это может произойти в современных версиях Windows с современными графическими устройствами и драйверами, хотя это не так часто, как в первые дни WPF. Вот почему одним из наших первых рекомендаций по тестированию и (или) обходу сбоя потока отрисовки является отключение аппаратного ускорения в WPF.
Возможно также, что сбой вызван тем, что приложение запрашивает отрисовку сцены, которая слишком сложна для обработки драйвера (или DirectX). Это не характерно для современных драйверов, но каждое устройство имеет ограничения, и это не невозможно, чтобы их превысить.
Другим историческим источником сбоев потоков отрисовки является использование свойств Window.AllowsTransparency или Popup.AllowsTransparency в WPF, что приведет к использованию многоуровневых окон . В более старых версиях Windows возникли проблемы с многоуровневыми окнами, но большинство из них были решены с появлением Диспетчера окон на рабочем столе (DWM) в Windows Vista.
Если сбой потока отрисовки проявляется как System.OutOfMemoryException , поток отрисовки, вероятно, стал жертвой процесса исчерпания некоторого ресурса. Поток отрисовки, вызываемый Win32/DX в API, который пытался выделить какой-то ресурс, но не удалось. WPF сопоставляет возвращаемые значения, такие как E_OUTOFMEMORY или ERROR_NOT_ENOUGH_MEMORY , System.OutOfMemoryException с . Хотя исключение относится к «памяти», сбой может относиться к любому типу ресурсов, например к дескрипторам объектов GDI, другим системным дескрипторам, памяти GPU, обычной памяти ОЗУ и т. д.
Примечания о сбоях выделения ресурсов
Два замечания относятся к System.OutOfMemoryException сбоям и к любому сбою выделения ресурсов.
- Первопричина может не заключаться в коде, который столкнулся со сбоем. Вместо этого в процессе может быть другой код, который чрезмерно потребляет ресурс, не оставляя ни одного из оставшихся для обычно успешного запроса.
- Если запрос необычно велик, сбой может произойти, несмотря на то, что ресурс выглядит в изобилии. Может System.OutOfMemoryException возникать, даже если в системе достаточно памяти, если есть запрос на большой объем (непрерывной) памяти. Вот реальный пример: подключаемый модуль Visual Studio готовился к восстановлению окна из состояния, сохраненного в предыдущем сеансе. Он неправильно корректировал разницу в DPI между предыдущим и текущим мониторами, что в 16 раз больше, чем должно было быть, с корректировками из нескольких слоев компонентов WPF, WindowsForms и VS window-hosting. Поток отрисовки попытался выделить буфер обратной передачи в 256 раз больше, чем требуется, и завершился ошибкой, несмотря на то, что доступной памяти для ожидаемого выделения было более чем достаточно.
Общие рекомендации
- Отключите аппаратную отрисовку, используя значение реестра DisableHWAcceleration , описанное в разделе Отключение аппаратного ускорения. Это повлияет на все приложения WPF на вашем компьютере; Это можно сделать только для проверки того, связана ли проблема с графическим оборудованием или драйверами. В этом случае проблему можно обойти, программно отключив аппаратное ускорение на более детальном уровне. Это можно сделать для каждого окна с помощью свойства HwndTarget.RenderMode или для каждого процесса с помощью свойства RenderOptions.ProcessRenderMode .
- Обновите видеодрайверы и (или) попробуйте другое видеоустройство на проблемных компьютерах.
- Обновите .NET до последней версии и уровня пакета обновления, доступных для целевой платформы.
- Обновление до последней версии операционной системы.
- Отключите использование Windows.AllowsTransparency и Popup.AllowsTransparency в приложении.
- Если System.OutOfMemoryExceptions об этом сообщается, отслеживайте использование памяти процесса в Монитор производительности, в частности счетчики ProcessVirtual Bytes, ProcessPrivate Bytes и .NET CLR Memory# во всех кучах. Мониторинг пользовательских объектов и объектов GDI для процесса в диспетчере задач Windows. Если вы определили, что определенный ресурс исчерпан, устраните неполадки с приложением, чтобы устранить чрезмерное потребление ресурсов. Имейте в виду два приведенных выше замечания о проблемах с выделением ресурсов.
- Если у вас есть воспроизводимый сценарий, который происходит на разных платформах или в разных сочетаниях видеоустройства и драйвера, возможно, возникла ошибка WPF. Обязательно соберите достаточно сведений, чтобы позволить провести исследование, прежде чем сообщить о проблеме в Корпорацию Майкрософт. Стека вызовов недостаточно. Корпорации Майкрософт требуются более подробные сведения, например:
- Полное решение VS с инструкциями по воспроизведению проблемы, включая описание среды — ОС, .NET и графики.
- Трассировка отладчика по времени проблемы.
- Полный аварийный дамп.
Обратная связь
Были ли сведения на этой странице полезными?
Источник: learn.microsoft.com
Получение OutofMemoryException во время выполнения с сообщением «Недостаточно памяти для продолжения выполнения программы»
Я получаю OutofMemoryException во время выполнения с сообщением “Недостаточно памяти для продолжения выполнения программы”. Я загружаю изображения в начале программы. Каждое изображение составляет 50+ МБ. Если размер изображений равен 277 Мбайт плюс, я получаю это исключение. Я загружаю изображения сразу, потому что я должен показывать их миниатюры в начале.
Я думал о кешировании и поисковом вызове. У меня есть возможность использовать больше памяти системы или как-то другое решение.
Лучший ответ:
Вероятно, вы могли бы попытаться позволить вашей программе получить доступ к большему количеству памяти, но это будет борьба. Для приложения .NET объем памяти контролируется параметром processModel/memoryLimit в файле machine.config. Корпорация Майкрософт рекомендует установить ее не более 60%.
Однако вы одновременно загружаете 50+ МБ изображений, чтобы отображать миниатюры (которые, вероятно, крошечные по размеру). Я предлагаю, чтобы вы сделали свое изменение. Вы можете загружать изображения один за другим, затем генерировать миниатюру и сразу освобождать память.
В любом случае наличие 50 МБ + изображений неэффективно, когда вы пытаетесь показать эскиз. Вы не можете просто сохранить эскизы и не генерировать их каждый раз?
Есть ли возможность использовать больше памяти системы или каким-то другим решением.
Переключение на 64-битное – это единственная простая опция.
Существует ограничение на 1GB на один объект на один объект (также применимо к 64-битным), но это не ваша проблема. Для создания объекта .NET необходимо, чтобы в процессе было достаточно непрерывной свободной памяти. Когда у вас есть несколько очень больших (более 250 МБ) больших объектов, все более маловероятно, что будет доступно постоянное адресное пространство.
- Используйте несколько процессов и межпроцессорных коммуникаций и mhash, при этом вся дополнительная сложность (особенно в случае сбоев).
- Загружать только одно изображение за раз.
- 64-битная.
Также читайте “Внутренние документы Windows” о том, как Windows управляет памятью, а затем о том, как .NET GC управляет памятью для фона. Не будет никакой замены для того, чтобы знать, что происходит, когда вы нажимаете столько данных вокруг. (Инструменты вроде VMMap помогут, но только если у вас есть основное понимание того, как все это работает.)
Источник: techarks.ru