이 문서는 ASP.NET 메모리 부족 오류를 해결하는 데 도움이 됩니다.
원래 제품 버전: ASP.NET
원래 KB 번호: 2020006
증상
Microsoft 고객 지원 서비스에서 볼 수 있는 가장 일반적인 문제 중 하나는 시나리오입니다 OutOfMemoryException
. 따라서 메모리 문제의 원인을 해결하고 식별하는 데 도움이 되는 리소스 컬렉션을 구성했습니다.
문제 해결 OutOfMemoryException
에 대한 세부 정보를 다루기 전에 이 문제의 원인을 파악하는 것이 중요합니다. 많은 개발자가 믿는 것과는 달리, 설치된 RAM의 양은 가능성과 OutOfMemoryException
는 영향을 주지 않습니다. 32비트 운영 체제는 상자에 설치된 실제 메모리 양에 관계없이 4GB의 가상 주소 공간을 처리할 수 있습니다. 이 중 2GB는 운영 체제(커널 모드 메모리)용으로 예약되고 2GB는 사용자 모드 프로세스에 할당됩니다. 커널 모드 메모리에 할당된 2GB는 모든 프로세스 간에 공유되지만 각 프로세스는 자체적으로 2GB의 사용자 모드 주소 공간을 가져옵니다. 모든 경우 스위치를 사용하도록 설정된 상태로 /3gb
실행되고 있지 않다고 가정합니다.
애플리케이션에서 메모리를 사용해야 하는 경우 가상 주소 공간의 청크를 예약한 다음 해당 청크에서 메모리를 커밋합니다. 관리되는 힙을 증가시키기 위해 메모리가 필요할 때 .NET Framework의 GC(가비지 수집기)가 수행하는 작업입니다. GC에 85KB 미만의 개체가 있는 작은 개체 힙에 새 세그먼트가 필요한 경우 64MB를 할당합니다. 큰 개체 힙에 새 세그먼트가 필요한 경우 16MB를 할당합니다. 이러한 큰 할당은 프로세스가 작동해야 하는 2GB 주소 공간의 연속 블록에서 충족되어야 합니다. 운영 체제가 연속 메모리 블록 System.OutOfMemoryException
에 대한 GC의 요청을 충족할 수 없는 경우 (OOM)이 발생합니다.
참고 항목
64비트 운영 시스템에서 실행되는 32비트 프로세스는 4GB의 사용자 모드 메모리를 처리할 수 있으며, 64비트 작업 시스템에서 실행되는 64비트 프로세스는 8TB의 사용자 모드 메모리를 처리할 수 있으므로 64비트 운영 시스템의 OOM은 가능성이 없으므로 64비트 운영 체제에서 실행되는 32비트 프로세스에서 OOM을 경험할 수 있지만, 일반적으로 프로세스가 3GB에 가까운 프라이빗 바이트를 사용할 때까지는 발생하지 않습니다.
OOM 조건이 표시되는 데는 두 가지 이유가 있습니다.
- 프로세스에서 많은 메모리를 사용하고 있습니다(일반적으로 32비트 환경에서는 800MB 이상).
- 가상 주소 공간이 조각화되어 연속된 대규모 할당이 성공할 가능성이 줄어듭니다.
1과 2의 조합으로 인해 OOM 조건을 볼 수도 있습니다. 자세한 내용은 ASP.NET System.OutOfMemoryExceptions 문제 해결을 참조하세요.
OOM이 발생하면 다음 증상 중 하나 이상을 확인할 수 있습니다.
애플리케이션이 충돌합니다. 자세한 내용은 이 OutOfMemory 사람이 누구이며 메모리가 많이 남았을 때 왜 내 프로세스가 충돌합니까?를 참조하세요.
작업 관리자 또는 성능 모니터 표시된 대로 애플리케이션에 높은 메모리가 발생할 수 있습니다.
요청을 처리하는 데 시간이 오래 걸릴 수 있습니다.
IIS(인터넷 정보 서비스) 7에서는 IIS 7에서 추적을 사용하여 실패한 요청 문제 해결을 사용하여 장기 실행 요청 문제를 해결할 수 있습니다.
사용자는 OOM 때문에 애플리케이션에서 오류 메시지를 보고할 수 있습니다.
OOM 조건의 원인을 결정할 때는 실제로 높은 메모리 상황 또는 조각난 주소 공간의 원인을 확인하기 위해 노력하고 있습니다. 이러한 상황의 가능한 원인을 모두 문서화할 수는 없지만 정기적으로 표시되는 몇 가지 일반적인 원인이 있습니다.
다음 정보는 OOM 조건의 일반적인 원인과 이러한 각 원인 해결에 대한 해결 방법에 대해 간략하게 설명합니다.
문자열 연결
관리되는 애플리케이션(.NET Framework를 사용하여 작성된 애플리케이션)의 문자열은 변경할 수 없습니다. 새 값이 문자열에 할당되면 복사본이 기존 문자열로 만들어집니다. 그리고 새 값이 새 문자열에 할당됩니다. 일반적으로 문제가 발생하지는 않습니다. 그러나 많은 수의 문자열이 연결되면 결국 개발자가 생각하는 것보다 더 많은 문자열 할당이 발생합니다. 그리고 메모리 증가 및 OOM 조건으로 이어질 수 있습니다.
문자열 연결로 인해 OOM을 방지하려면 클래스를 사용하고 StringBuilder
있는지 확인합니다. 자세한 내용은 Visual C#에서 문자열 연결 성능을 개선하는 방법을 참조하세요.
관리되는 힙의 조각화
관리되는 애플리케이션의 GC(가비지 수집기)는 조각화 양을 줄이기 위해 힙을 압축합니다. 그러나 관리되는 애플리케이션에서 개체를 고정할 수 있습니다. 고정된 개체는 힙 압축 중에 이동할 수 없습니다. 이렇게 하면 개체가 있는 주소가 변경됩니다. 애플리케이션이 많은 수의 개체를 고정하거나 개체를 오랫동안 고정하는 경우 관리되는 힙에서 조각화가 발생할 수 있습니다. GC가 관리되는 힙을 더 자주 증가시키고 OOM 조건을 유발할 수 있습니다.
.NET Framework 1.0 이후 고정으로 인해 OOM 조건을 최소화하기 위해 노력했습니다. 각 버전에서 증분 개선이 이루어졌습니다. 그러나 개체를 고정해야 하는 경우 유용한 디자인 패턴을 구현할 수 있습니다.
VA(가상 주소) 공간의 조각화
각 프로세스에는 할당된 특정 양의 메모리가 있으며 해당 메모리는 프로세스에 대한 VA 공간을 나타냅니다. VA 공간이 조각화되면 GC가 관리되는 힙을 증가시키기 위해 연속 메모리의 큰 블록을 얻을 수 없을 가능성이 높아집니다. 그리고 OOM 조건으로 이어질 수 있습니다.
VA 공간의 조각화는 다음 시나리오 중 하나 이상에 의해 발생하는 경우가 많습니다.
동일한 어셈블리를 여러 애플리케이션 도메인에 로드합니다.
동일한 애플리케이션 풀에서 실행되는 둘 이상의 애플리케이션에서 어셈블리를 사용해야 하는 경우 어셈블리의 이름을 강하게 지정하고 GAC에 설치합니다. 이렇게 하면 어셈블리가 프로세스에 한 번만 로드되는지 확인합니다.
요소의 디버그 특성을 사용하여 프로덕션 환경에서 애플리케이션을
<compilation>
실행합니다true
.- 요소의
<compilation>
디버그 특성은 프로덕션에 있을 때여야false
합니다. - 구성을
<deploy retail="true" />
사용하여 제품에서 디버그를 항상 사용하지 않도록 설정할 수 있습니다. 자세한 내용은 배포 요소(ASP.NET 설정 스키마)를 참조하세요.
- 요소의
XSL(eXtensible Style sheet Language) 변환 또는 만들기
XmlSerializers
내에서 스크립팅을 사용합니다.이 경우 XSLT(Extensible Style sheet Language Transformations) 스크립팅 또는
XmlSerializers
.
대용량 데이터 집합 반환
데이터베이스 또는 다른 데이터 원본의 데이터를 사용하는 경우 반환되는 데이터의 양을 제한하는 것이 중요합니다. 예를 들어 필요할 때 데이터베이스에서 데이터의 일부를 검색하는 비용을 방지하기 위해 전체 데이터베이스 테이블을 반환하는 쿼리 결과를 캐싱하는 것은 좋은 방법이 아닙니다. 이렇게 하면 메모리가 쉽게 높아지고 OOM 상태가 발생할 수 있습니다. 사용자가 비슷한 쿼리를 시작할 수 있도록 허용하는 것은 높은 메모리 상황을 만드는 또 다른 일반적인 방법입니다. 예를 들어 회사의 모든 직원 또는 텍사스 주의 모든 고객에게 문자 S로 시작하는 성을 반환합니다.
항상 데이터베이스에서 반환할 수 있는 데이터의 양을 제한합니다. 그런 다음 페이지에 표시되는 데이터의 양을 제어할 수 없기 때문에 쿼리 SELECT * FROM. . .
를 허용하지 않습니다.
GridView 컨트롤과 같은 UI 요소에 큰 데이터 결과를 표시하지 않도록 하는 것이 중요합니다. 반환된 데이터에 필요한 메모리 외에도 결과를 렌더링하는 데 필요한 많은 양의 데이터를 문자열 및 UI 요소에서 사용합니다. 큰 데이터 집합이 반환되지 않도록 페이징을 구현하고 입력의 유효성을 검사하면 이 문제를 방지할 수 있습니다.
추적을 사용하도록 설정된 프로덕션 환경에서 실행
ASP.NET 추적은 애플리케이션 문제 해결을 위한 강력한 기능입니다. 그러나 프로덕션 환경에서는 절대로 남아서는 안 됩니다. ASP.NET 추적은 추적 정보를 저장하는 것과 같은 DataTables
데이터 구조를 사용하며 시간이 지남에 따라 OOM으로 이어질 수 있는 높은 메모리 조건을 일으킬 수 있습니다.
프로덕션 환경에서 추적을 사용하지 않도록 설정해야 합니다. web.config 파일에서 enabled
요소의 <trace>
특성을 false로 설정하여 이 작업을 수행할 수 있습니다. 소매 배포를 사용하도록 <deploy retail="true" />
설정하면 애플리케이션에서 추적도 사용하지 않도록 설정됩니다.
네이티브 리소스 누수
많은 관리되는 리소스도 네이티브 리소스를 사용합니다. GC는 네이티브 리소스를 정리하지 않으므로 개발자는 Dispose 메서드를 구현하고 호출하여 네이티브 리소스를 정리할 책임이 있습니다. 인터페이스를 구현 IDisposable
하는 형식을 사용하고 메서드를 호출 Dispose
하지 않는 경우 네이티브 리소스가 누출되고 OOM 조건이 발생할 위험이 있습니다.
이러한 개체는 인터페이스를 iDisposable
구현해야 하며 더 이상 필요하지 않은 경우 이러한 개체에서 메서드를 호출 Dispose
해야 합니다.