2010-03-08 2 views
11

다른 미지의 가능성이있는 LOH 단편화를 포함 할 수있는 희망없는 메모리 문제에 대해서는 다른 활성 질문 HERE이 있습니다.대용량 배열 및 LOH 단편화. 수락 된 국제 대회는 무엇입니까?

지금 제 질문은 무엇이 허용되는 방식입니까? 내 응용 프로그램이 Visual C#에서 수행되어야하고 int [4000000]의 튜닝을 위해 큰 배열을 처리해야하는 경우 어떻게 이 아닌가? 가비지 수집기의 LOH 처리를 거부 할 수 있습니까?

큰 배열을 전역으로 만들 것을 강요당하는 것처럼 보일 수 있으며, 그 중 어느 하나에도 "new"라는 단어를 사용하지 않는 것 같습니다. 그래서, 함수에 의해 전달되는 깔끔하게 크기가 정해진 배열 대신에 "maxindex"변수를 가진 유망한 전역 배열이 남아 있습니다.

나는 이것이 항상 나쁜 습관이라고 들었다. 어떤 대안이 있습니까?

System.GC.CollectLOH("Seriously")의 곡에는 어떤 종류의 기능이 있습니까? 가비지 수집을 System.GC 이외의 다른 방법으로 아웃소싱 할 수있는 방법이 있습니까?

어쨌든 큰 (> 85Kb) 변수를 처리하기 위해 일반적으로 받아 들여지는 규칙은 무엇입니까?

답변

22

먼저 가비지 컬렉터 에 LOH를 수집합니다. 따라서 LOH를 수집하므로 즉시 해당 프레젠테이션을 두려워하지 마십시오. LOH는 2 세대가 수집되면 수집됩니다.

차이점은 LOH가 압축되지 않는다는 것입니다. 즉, 수명이 긴 개체가 있으면 LOH를 실제로 두 영역으로 나눌 것입니다. 즉, 이전 영역과 이후 영역 목적. 이 동작은 다음 일이 계속되면 당신은 LOH 즉, 수명이 긴 물체 사이의 공간이 이후의 과제와 .NET이 큰 개체를 배치하기 위해 더 많은 메모리를 할당하는 충분히 크지 않은 상황으로 끝날 수있다 조각난다.

이제 말하자면, LOH의 끝 부분에 살아있는 물체가 완전히 없으면 LOH가 축소 될 수 있으므로 유일한 문제는 오랫동안 물체를 거기에 넣어두면 문제가되는 것입니다 (예 : 신청). LOH의 단편화를 방지하기

전략은 다음과 같습니다 놀아 큰 개체를 만드는

  • 마십시오. 기본적으로 이는 큰 배열 또는 바이트 배열을 래핑하는 MemoryStream과 같은 큰 배열을 감싸는 객체입니다. 복잡한 객체의 구성 요소는 별도로 힙에 저장되므로 거의 없습니다. 이것들은 내부적으로 배열을 사용하기 때문에 큰 사전과 목록에주의하십시오.
  • 이중 배열에주의하십시오. LOH에 들어가는 임계 값은 훨씬 더 작습니다. 정확한 숫자는 기억할 수 없지만 수천 개에 불과합니다.
  • MemoryStream이 필요한 경우 하나의 거대한 배열 대신 여러 개의 작은 배열로 백업되는 청크 분할 버전을 고려하십시오. 당신은 또한 chirking을 사용하여 LOW에서 끝나는 것을 피하기 위해 IList와 IDictionary의 커스텀 버전을 만들 수 있습니다.
  • Remoting은 통화 기간 동안 LOH를 조각 낼 수있는 MemoryStream을 많이 사용하기 때문에 매우 긴 Remoting 호출을 피하십시오.
  • 는 인턴 문자열을 조심 - 어떤 이유로이가 LOH의 페이지로 저장됩니다 심각한 분열을 일으킬 수 있습니다 응용 프로그램이 인턴 새로운 문자열을 발생하는 것을 계속하는 경우 문자열의 집합을 알고하지 않으면, 즉 string.Intern을 사용하지 마십시오 유한하고 응용 프로그램의 초기에 풀 세트가 발생합니다. (my earlier question을 참조하십시오.)
  • Stohke의 Son을 사용하여 LOH 메모리를 정확히 사용하는지 확인하십시오. 더 자세한 방법은 this question을 참조하십시오.

편집 : 이중 배열의 LOH 임계 값은 8k로 나타납니다.

+0

이것은 가장 좋은 질문 일 수 있습니다 ...하지만 어떻게 CDB와 SOS를 얻을 수 있습니까? Google은 모르는 것 같습니다. "CDB 다운로드"를 따르는 모든 링크는 CDB처럼 들리지 않는 "DDK3"목록의 일부 MSDN 검색 결과 페이지를 가리 킵니다. –

+1

다운로드 'Windows 용 디버깅 도구'. CDB는 콘솔 디버거이며 WinDbg는 '그래픽'과 동일합니다 (텍스트 모드이지만 MDI 창에서 렌더링 됨). SOS는 .NET과 함께 제공됩니다 : '% systmeroot % \ microsoft.net \ framework \ v2.0.50727 \ sos.dll'(.NET 3은 .NET 2 SOS.dll을 사용하고 .NET 4는 자체 버전을 제공합니다.) –

+2

또한 , Visual Studio의 직접 실행 창에서 SOS를로드 할 수 있습니다 (CDB 필요 없음).하지만 절대로 시도한 적이 없습니다. –

5

가장 먼저 떠오르는 것은 배열을 더 작은 배열로 나눠서 GC에 LOH를 넣는 데 필요한 메모리에 도달하지 못하게하는 것입니다. 어레이를 10,000 개 정도의 작은 배열로 침을 뱉어서 통과시킨 인덱서를 기반으로 어떤 배열을 볼 것인지를 아는 개체를 만들 수 있습니다.

이제는 코드를 보지 못했지만 왜 커다란 배열이 필요한지에 대해서도 질문 할 것입니다. 잠재적으로 코드를 리팩터링하여 모든 정보를 메모리에 한 번에 저장할 필요가 없습니다.

+0

내 응용 프로그램 가능한 크기 1024x720의 이미지에 걸리는 System.Runtime 네임 스페이스에서 발견 될 수 있고, 그 변환하여 픽셀 강도에 기초하여 "높이"의 행렬이다. 그런 다음이 행렬을 사용하여 OpenGL에서 표면지도를 렌더링합니다. 그래서, 나는 그 모든 자료를 동시에 필요로합니다. –

5

잘못되었습니다. 배열 크기가 4000000 일 필요는 없으며 garbace 수집기를 호출 할 필요가 없습니다.

  • 독자적인 IList 구현을 작성하십시오. "PagedList"와 비슷합니다.
  • 항목을 65536 개의 요소 배열로 저장합니다.
  • 페이지를 보유 할 배열의 배열을 만듭니다.

기본적으로 하나의 리디렉션 만 사용하여 모든 요소에 액세스 할 수 있습니다. 그리고 개별 배열이 작을수록 조각화는 문제가되지 않습니다 ...

... 만약 그렇다면 ... 다시 페이지를 참조하십시오. 그 (것)들을 멀리 처분하지 말라, 정체되는 "PageList"에 그 (것)들을두고 거기에서 첫째로 당기십시오. 이 모든 것은 수업 내에서 투명하게 수행 될 수 있습니다.

정말 좋은 점은이 목록은 메모리 사용량면에서 꽤 역동적이라는 것입니다. 홀더 배열 (리디렉터)의 크기를 조정할 수 있습니다. 그렇지 않은 경우에도 페이지 당 약 512kb 데이터입니다.

2 차 레벨 배열은 기본적으로 클래스 당 8 바이트 (페이지 당 512kb, 32 비트에서 256kb) 또는 구조 바이트 당 64kb입니다.기술적으로

:

전원을 켜고 INT [] INT는 [] []

은 당신이 원하는대로 32 또는 64 비트가 더 여부를 결정 로) ahve 장점과 단점 모두를.

그런 큰 배열 하나를 다루는 것은 모든 언어에서 다루기 힘들다. 만약에 당신이 꿈꾸면, 기본적으로 .... 프로그램 시작시 할당하고 결코 다시 생성하지 말라. 유일한 해결책.

+0

그래서, 들쭉날쭉 한 배열 int [] []는 연속적인 메모리를 사용할 필요가 없습니까? int [,]와 같은 배열은 같은 방식으로 동작합니까? –

+0

새로운 int [,]는 하나의 인접한 블록을 할당한다고 생각합니다. 가변 배열은 별도로 할당됩니다. –

0

문제가 발생할 수있는 방법에 관해서는 위의 대답을 자세히 설명하고 있습니다.LOH의 단편화는 오랫동안 존재하는 객체에 의존 할뿐만 아니라 여러 스레드가 있고 각각이 LOH로가는 큰 목록을 작성하는 상황이 발생하면 첫 번째 스레드 목록을 증가시킬 필요가 있지만 연속적인 다음 비트의 메모리는 이미 두 번째 스레드의 List에 의해 처리되므로 런타임은 첫 번째 스레드 List에 새로운 메모리를 할당하여 다소 큰 구멍을 남깁니다. 이것은 내가 상속 한 프로젝트에서 현재 일어나고있는 것이므로 LOH가 약 4.5MB이지만 런타임에는 총 117MB의 여유 메모리가 있지만 최대 여유 메모리 세그먼트는 28MB입니다.

또 다른 방법은 다중 스레드없이 발생할 수 있습니다. 어떤 종류의 루프에 둘 이상의 목록이 추가되고 처음에 할당 된 메모리를 넘어서 확장 될 때 각각이 커지면서 다른 하나를 뛰어 넘는 것입니다. 할당 된 공간 이상으로

유용한 링크입니다 : 아직도 이것에 대한 해결책을 찾고 https://www.simple-talk.com/dotnet/.net-framework/the-dangers-of-the-large-object-heap/

, 하나의 옵션이 작업을 수행 할 때 풀에서 어떤 풀링 된 객체의 종류 및 요청을 사용할 수 있습니다. 큰 배열을 다루는 경우 다른 옵션은 맞춤 컬렉션을 개발하는 것입니다. 컬렉션 모음이므로 하나의 거대한 목록 만 가지지 않고 LOH를 피하는 작은 목록으로 나눕니다.

5

이전 질문이지만 .NET에서 도입 된 변경 사항으로 답변을 업데이트하는 것이 쉽지 않은 것으로 나타났습니다. 이제 대형 오브젝트 힙을 조각 모음 할 수 있습니다. 분명히 첫 번째 선택은 최고의 디자인 선택이 이루어 졌는지 확인하는 것이지만 지금은이 옵션을 사용하는 것이 좋습니다.

https://msdn.microsoft.com/en-us/library/xe0c2357(v=vs.110).aspx

"은 .NET Framework 4.5.1을 시작으로, 다음과 같이 수집 메서드를 호출하기 전에 GCLargeObjectHeapCompactionMode.CompactOnce에 GCSettings.LargeObjectHeapCompactionMode 속성을 설정하여 대형 개체 힙 (LOH)을 압축 할 수 있습니다 예를 보여줍니다. "

GCSettings가

GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce; 
GC.Collect();