Вопрос или проблема
Иногда, при пересборке моего решения, я получаю следующую ошибку. Решение огромное, более 270 проектов, и у меня нет идеи, как избавиться от этой ошибки. Это происходит иногда, чаще всего решение компилируется правильно. У меня 32ГБ ОЗУ, так что это не проблема, у меня также есть ReSharper, а у друга на работе его нет, и он никогда не испытывал эту ошибку, так что, возможно, в этом проблема. В любом случае, если кто-то имеет идею, как это исправить, я был бы очень рад услышать об этом 😉
C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\MSBuild\Microsoft\VisualStudio\v15.0\SSDT\Microsoft.Data.Tools.Schema.SqlTasks.targets(559,5): Ошибка: MSB4018: Задача “SqlBuildTask” завершилась неожиданной ошибкой. 31>Microsoft.Data.Tools.Schema.Sql.Build.BuildFailedException: Исключение типа ‘System.OutOfMemoryException’ было выброшено. —> System.OutOfMemoryException: Исключение типа ‘System.OutOfMemoryException’ было выброшено.
Это похоже на известную проблему, о которой сообщалось в
Неограниченные экземпляры/подключения SQLite, способствующие сбоям из-за недостатка памяти #22650.
Проблема, видимо, была решена в версии 15.5 Visual Studio 2017, и исправление могло быть перенесено на 15.4.
Обновление Visual Studio 2017 до последней версии должно решить проблему
(если это действительно то же самое).
Поскольку это не решило проблему, стоит отметить, что ошибка
OutOfMemoryException не означает нехватку памяти, а скорее
невозможность выделить память.
Я объясню ниже, почему это не одно и то же.
Так как Visual Studio является 32-битной программой, её адресное пространство ограничено 4 ГБ.
Из этого она может “только” использовать около 2 ГБ для своих данных, остальное используется
программами и программным обеспечением Windows.
Физической памяти выделяются виртуальные адреса в этом пространстве, так что
некоторые адреса уже выделены, а некоторые – нет.
Механизм сборки мусора невозможен, так что адрес,
один раз выделенный, остается выделенным.
Представьте, например, что из доступных 2 ГБ 100 МБ
выделены, и кто-то хочет выделить дополнительный 1 ГБ.
Логически доступной памяти гораздо больше, чем достаточно.
Тем не менее, если 100 МБ выделены посреди пространства в 2 ГБ,
уже невозможно выделить 1 ГБ контiguous памяти.
В этом случае возникнет условие OutOfMemoryException,
хотя это кажется совершенно невозможным.
Этот случай может возникнуть, когда память выделяется и освобождается таким образом,
что выделенные фрагменты памяти разбросаны по доступному
адресному пространству и оставляют только “дыры”, которые недостаточны для большого
выделения.
Поэтому есть только две возможности:
-
Ошибка в Visual Studio, например, при попытке увеличить
длину экземпляра классаStringBuilder
Beyond указанного в его текущейMaxCapacity
property, также приведет к условию OutOfMemoryException. -
Слишком много выделений памяти, так что даже освобожденная память слишком фрагментирована.
Ваш случай, похоже, лучше соответствует второму случаю, но ваши варианты решения здесь довольно ограничены.
64-битная версия Visual Studio решила бы проблему, увеличив
адресное пространство, но этого нет в
Плане Visual Studio.
Ваш другой вариант – сократить выделение памяти насколько возможно.
Вы можете уменьшить количество дополнений для Visual Studio или попробовать
разбить это огромное решение VS на более мелкие.
Или вы можете закрыть и перезапустить Visual Studio, так как некоторые выделения памяти
осуществляются параллельно потоками Visual Studio, так что есть случайный
элемент.
Ответ или решение
Проблема, с которой вы сталкиваетесь, заключается в неожиданном сбое задачи "SqlBuildTask" в Visual Studio, возникающем с исключением System.OutOfMemoryException
. Это довольно распространенная проблема для проектов, где используется большое количество ресурсов, и две ключевые причины могут лежать в ее основе: фрагментация памяти и ограничения, связанные с 32-разрядной архитектурой Visual Studio.
Причины возникновения System.OutOfMemoryException
-
Фрагментация памяти:
- Даже при наличии достаточного объема оперативной памяти (в вашем случае 32 ГБ) OutOfMemoryException может возникнуть из-за фрагментации доступного адресного пространства. В 32-разрядных приложениях, таких как Visual Studio, доступное пространство ограничено 4 Гб, и фактически только около 2 Гб выделяется для ваших данных. Это значит, что если память распределена неэффективно, то освободившиеся участки памяти могут оказаться недостаточно большими для выполнения новой операции.
-
Ограничения 32-разрядной архитектуры:
- Visual Studio 2017 является 32-разрядным приложением, что накладывает ограничения на выделение памяти, даже если физическая память на вашем компьютере не исчерпана. Как только приложение начинает использовать выделенную память, оно сталкивается с проблемами при попытке выделить большие блоки памяти, особенно если в этом пространстве уже имеется много различных выделенных блоков, которые могут мешать выделению новой большой области памяти.
Потенциальные решения
-
Обновление Visual Studio:
- Первым шагом должно быть обновление Visual Studio до последней доступной версии. Это поможет исправить известные ошибки, связанные с утечками памяти и фрагментацией, которые могут вызывать такие исключения, как
System.OutOfMemoryException
. В частности, обращайте внимание на исправления, размещенные в версиях 15.4 и 15.5, так как они были направлены на решение этой проблемы.
- Первым шагом должно быть обновление Visual Studio до последней доступной версии. Это поможет исправить известные ошибки, связанные с утечками памяти и фрагментацией, которые могут вызывать такие исключения, как
-
Уменьшение объема распределения памяти:
- Попробуйте минимизировать использование расширений и дополнений, таких как ReSharper, которые могут потреблять значительные объемы памяти. Если это возможно, отключите их во время сборки.
-
Разбиение решения:
- Рассмотрите возможность разделения вашего решения на меньшие части. Это может уменьшить объем памяти, необходимый для сборки и управления проектом. Это также может повысить производительность и снизить риск возникновения ошибок сборки.
-
Частая перезагрузка Visual Studio:
- Перезагрузка Visual Studio может помочь устранить накопленную фрагментацию памяти. Убедитесь, что после каждой крупной сборки вы перезагружаете приложение, чтобы освободить память.
-
Мониторинг и профилирование:
- Используйте инструменты мониторинга и профилирования памяти для визуализации распределения памяти в вашем проекте. Это поможет вам определить, где происходит наибольшее потребление памяти, и где может быть проблема.
Заключение
Ошибка System.OutOfMemoryException
— это симптом потенциальных проблем с управлением памятью в большом и сложном проекте, как ваш. Реализация предложенных мер может помочь вам минимизировать вероятность возникновения данной проблемы в будущем. Не забывайте также регулярно проверять изменения и обновления от Microsoft, так как сообщество и разработчики продолжают работать над улучшением Visual Studio и устранением подобных ошибок.