C # : 메모리 부족 예외
오늘 내 응용 프로그램은 OutOfMemoryException
. 나에게 이것은 4GB RAM과 많은 가상 메모리를 가지고 있기 때문에 항상 거의 불가능했습니다. 새 목록에 기존 컬렉션을 추가하려고 할 때 오류가 발생했습니다.
List<Vehicle> vList = new List<Vehicle>(selectedVehicles);
내 이해에는 새 목록에 포함되어야하는 차량이 이미 메모리 내부에 존재하기 때문에 여기에 할당 된 메모리가 많지 않습니다. 나는 Vehicle
매우 복잡한 수업이라는 것을 인정해야하는데 한 번에 약 50.000 개의 항목을 새 목록에 추가하려고했습니다. 그러나 Vehicle
응용 프로그램의 모든 s는 크기가 200MB에 불과한 데이터베이스에서 가져 오기 OutOfMemoryException
때문에이 시점에서 어떤 원인 이 될 수 있는지 알 수 없습니다 .
두 가지 사항 :
- 32 비트 Windows를 실행하는 경우 모든 4GB에 액세스 할 수있는 것이 아니라 2GB 만 사용할 수 있습니다.
- 의 기본 구현이
List
배열 이라는 것을 잊지 마십시오 . 메모리가 심하게 조각난 경우List
전체적으로 사용 가능한 메모리 가 충분하더라도을 할당하기에 충분한 연속 공간이 없을 수 있습니다 .
3 년 된 주제이지만 다른 작업 솔루션을 찾았습니다. 여유 메모리가 충분하고 64 비트 OS를 실행 중이며 여전히 예외가 발생하는 경우 Project properties
-> Build
탭으로 이동 x64
하여 Platform target
.
.Net4.5 에는 더 이상 객체에 대한 2GB 제한이 없습니다. 이 줄을 App.config에 추가하십시오.
<runtime>
<gcAllowVeryLargeObjects enabled="true" />
</runtime>
OutOfMemoryException 없이 매우 큰 객체를 생성 할 수 있습니다.
x64 OS에서만 작동합니다!
애플리케이션의 메모리와 비교하여 데이터베이스에 저장된 데이터는 매우 다릅니다.
개체의 정확한 크기를 얻는 방법은 없지만 다음과 같이 할 수 있습니다.
GC.GetTotalMemory()
일정량의 개체가로드 된 후 목록을로드 할 때 메모리가 얼마나 변경되는지 확인합니다.
과도한 메모리 사용량의 원인이 목록이라면이를 최소화하는 방법을 살펴볼 수 있습니다. 예를 들어, 처음에 50,000 개의 객체를 한 번에 모두 메모리에로드하기를 원하십니까? 필요에 따라 DB에 전화하는 것이 가장 좋지 않습니까?
http://www.dotnetperls.com/array-memory 를 살펴보면 .NET의 개체가 실제 데이터보다 크다는 것을 알 수 있습니다. 일반적인 목록은 배열 이라기보다 메모리를 많이 사용합니다. 개체 내부에 일반 목록이 있으면 훨씬 빠르게 증가합니다.
OutOfMemoryException (32 비트 컴퓨터에서)은 메모리에 대한 실제 하드 제한만큼 자주 조각화에 관한 것입니다. 이에 대해 많은 것을 찾을 수 있지만 여기에 대해 간략하게 설명하는 첫 번째 Google 조회수가 있습니다. http://blogs.msdn.com/b /joshwil/archive/2005/08/10/450202.aspx . (@Anthony Pegram은 위의 의견에서 동일한 문제를 언급하고 있습니다).
즉, 위의 코드에서 떠오르는 또 다른 가능성이 있습니다. "IEnumerable"생성자를 List에 사용하고 있으므로 전달하는 컬렉션의 크기에 대한 힌트를 개체에 제공하지 않을 수 있습니다. List 생성자에. 전달하는 객체가 컬렉션이 아닌 경우 ( ICollection
인터페이스를 구현하지 않음 ) 뒤에서 List 구현은 매번 너무 작은 배열을 남겨두고 여러 번 (또는 여러 번) 성장해야합니다. 쓰레기 수거가 필요합니다. 가비지 수집기는 아마도 버려진 배열에 충분히 빨리 도달하지 못할 것이며 오류가 발생할 것입니다.
The simplest fix for this would be to use the List(int capacity)
constructor to tell the framework what backing array size to allocate (even if you're estimating and just guessing "50000" for example), and then use the AddRange(IEnumerable collection)
method to actually populate your list.
So, simplest "Fix" if I'm right: replace
List<Vehicle> vList = new List<Vehicle>(selectedVehicles);
with
List<Vehicle> vList = new List<Vehicle>(50000);
vList.AddRange(selectedVehicles);
All the other comments and answers still apply in terms of overall design decisions - but this might be a quick fix.
Note (as @Alex commented below), this is only an issue if selectedVehicles
is not an ICollection.
My Development Team resolved this situation:
We added the following Post-Build script into the .exe project and compiled again, setting the target to x86 and increasing by 1.5 gb and also x64 Platform target increasing memory using 3.2 gb. Our application is 32 bit.
Related URLs:
- http://www.guylangston.net/blog/Article/MaxMemory
- .NET Out Of Memory Exception - Used 1.3GB but have 16GB installed
Script:
if exist "$(DevEnvDir)..\tools\vsvars32.bat" (
call "$(DevEnvDir)..\tools\vsvars32.bat"
editbin /largeaddressaware "$(TargetPath)"
)
You should not try to bring all the list at once, te size of the elements in the database is not the same that the one it takes into memory. If you want to process the elements you should use a for each loop and take advantage of entity framework lazy loading so you dont bring all the elements into memory at once. In case you want to show the list use pagination (.Skip() and .take() )
While the GC compacts the small object heap as part of an optimization strategy to eliminate memory holes, the GC never compacts the large object heap for performance reasons**(the cost of compaction is too high for large objects (greater than 85KB in size))**. Hence if you are running a program that uses many large objects in an x86 system, you might encounter OutOfMemory exceptions. If you are running that program in an x64 system, you might have a fragmented heap.
I know this is an old question but since none of the answers mentioned the large object heap, this might be of use to others who find this question ...
Any memory allocation in .NET that is over 85,000 bytes comes from the large object heap (LOH) not the normal small object heap. Why does this matter? Because the large object heap is not compacted. Which means that the large object heap gets fragmented and in my experience this inevitably leads to out of memory errors.
In the original question the list has 50,000 items in it. Internally a list uses an array, and assuming 32 bit that requires 50,000 x 4bytes = 200,000 bytes (or double that if 64 bit). So that memory allocation is coming from the large object heap.
So what can you do about it?
If you are using a .net version prior to 4.5.1 then about all you can do about it is to be aware of the problem and try to avoid it. So, in this instance, instead of having a list of vehicles you could have a list of lists of vehicles, provided no list ever had more than about 18,000 elements in it. That can lead to some ugly code, but it is viable work around.
If you are using .net 4.5.1 or later then the behaviour of the garbage collector has changed subtly. If you add the following line where you are about to make large memory allocations:
System.Runtime.GCSettings.LargeObjectHeapCompactionMode = System.Runtime.GCLargeObjectHeapCompactionMode.CompactOnce;
it will force the garbage collector to compact the large object heap - next time only.
It might not be the best solution but the following has worked for me:
int tries = 0;
while (tries++ < 2)
{
try
{
. . some large allocation . .
return;
}
catch (System.OutOfMemoryException)
{
System.Runtime.GCSettings.LargeObjectHeapCompactionMode = System.Runtime.GCLargeObjectHeapCompactionMode.CompactOnce;
GC.Collect();
}
}
of course this only helps if you have the physical (or virtual) memory available.
.Net이 발전함에 따라 모든 사람을 끌어들이는 새로운 32 비트 구성을 추가 할 수있는 능력도있는 것 같습니다.
.Net Framework 4.7.2를 사용하는 경우 다음을 수행하십시오.
프로젝트 속성으로 이동
짓다
'32 비트 선호 '를 선택 취소하십시오.
건배!
참고 URL : https://stackoverflow.com/questions/8563933/c-sharp-out-of-memory-exception
'Programing' 카테고리의 다른 글
How to get file path using Storage facade in laravel 5? (0) | 2020.11.19 |
---|---|
UINavigationBar에서 UIBarButtonItem의 위치 변경 (0) | 2020.11.19 |
C #으로 문자열에서 텍스트 찾기 (0) | 2020.11.19 |
기존 테이블에 자동 증가 ID를 추가 하시겠습니까? (0) | 2020.11.19 |
B-tree faster than AVL or RedBlack-Tree? (0) | 2020.11.19 |