Home .NET GC 정리(1)
Post
Cancel

.NET GC 정리(1)

.NET GC 정리(1)

인터넷 여기저기 흩어져있는 GC 관련정보 정리 1탄.

틀린게 있다면 말해주세요.


누구나 아는 내용

다음은 누구나 아는 내용이고 .NET 버전이 달라져도 동일한 내용 (.NET 7까지는..)

  • CLR이 제공하는 메모리 수집 기능 GC

    C#, ASP.NET 등 .NET 환경에서 개발한 프로그램은 CLR(Common Language Runtime) 위에서 프로그램이 돌아간다. 메모리 수집을 사용자가 아닌 CLR이 맡아서 하게된다. 이 기능을 GC라고 한다.

  • .NET의 GC는 Mark/Swap 방식

    메모리를 해제하는 방법에는 크게 Reference count와 Mark and sweep 기법이 있다. .NET은 Mark and sweep 기법을 사용한다. 사용하고 있는 객체를 마킹하고 마킹이 없는 메모리를 전부 해제한다.

  • .NET은 세대별 GC

    • Mark/Sweep 기법은 메모리를 뒤지며 해제해도 되는 객체를 찾아야한다. 메모리를 전부 뒤지는 것은 비용이 어마어마하므로 최근에 생성한 객체만 우선 정리하기 위해 메모리를 세대로 나눈 기법.
  • GC는 힙 메모리가 부족할 때 발생한다 (다른 경우도 있음)

    • 스택영역은 콜스택이 끝나면 (= 코드 블록이 끝나는 시점) 알아서 사라지므로 GC가 회수할 필요가 없다.
    • 새로운 객체를 만들때 공간이 부족하면 (=남은 공간이 threshold를 넘을 경우) (threshold는 실행중 계속 업데이트된다.) GC를 시작한다. —

이제부터는 헷갈리는 주제들을 하나씩 정리해보고자 한다.

SOH / LOH / POH

.NET 5버전부터 도입된 POH 개념과 함께 힙메모리는 위와 같이 3가지로 나뉜다.

SOH : 기본적으로 객체가 할당되는 0~2세대로 나뉜 힙

LOH : 큰객체(85,000 바이트 이상)가 할당되는 영역.

POH :

  • fixed, unsafe, 소켓 버퍼 등 주소를 고정되는 객체를 보관하기 위해 만들어진 영역. 사용자가 직접 API (GC.AllocateArray) 등.. 를 통해 객체를 할당할 수 있는 영역.

  • pin된 객체는 API를 콜하지않으면 SOH, LOH, POH 어디든 있을 수 있다. pin 되었다고 POH에 들어가는게 아니다.

GC Generations / Segment

(주의).NET 7부터는 Segment 대신 Region이라는 구조로 변경되었습니다.

  • 0, 1 세대는 임시 세대(ephemeral generations)라고 불린다.

  • 2세대는 임시세그먼트에 머무르고있다가 공간이 부족해지면 Gen2 세그먼트로 이동한다.

  • 임시 세그먼트는 1개로 고정이지만, 2세대 세그먼트는 부족하면 메모리(또는 주소공간)가 있는한 계속해서 늘어난다

  • Commited 영역은 메모리를 점유하고 있고 0으로 초기화되어 바로 사용가능한 영역. 메모리를 실제로 점유하고 있는 상태.

  • Reserved 영역은 주소공간만 예약한 상태. 메모리는 차지하지 않고있음.

  • LOH, POH는 묶어서 UOH(User Old Heap)라고 불린다.

  • pin되어 있는 객체는 주소가 고정되어 GC의 Compaction을 방해한다. (아래 그림 1세대의 지저분한 pinned 객체를 보자 흑흑)

segment image 세그먼트 구조

Segment / Region

.NET 7부터 Segment대신 Region 구조를 사용해 힙을 관리한다.

참고 원문: maoni 포스팅

기존 세그먼트는 크기가 커서 여유 메모리를 관리하기 어려워 Region이라는 작은 단위로 메모리를 효율적으로 관리하도록 개선한 구조.

  • 환경마다 다르지만 SOH 세그먼트가 1GB 인것에 비해 Region은 4MB.

  • 블로그 포스팅의 주 내용은 메모리를 얼마만큼이나 Commited 해놓을까에 대한 고찰이다. Commited를 많이해두면 할당을 빠르게 할 수는 있지만 그만큼 메모리를 차지하기 때문에 Commited 영역은 계속해서 업데이트 된다.

  • Segement는 세대별로 나누어진 메모리를 다른 세대간 공유할 수 없지만 Region은 세대간 공유가능하다.

WorkStation GC / Server GC

.NET의 GC는 WGC(WorkStation GC), SGC(Server GC)로 나뉘는데 둘의 차이는 간단하다.

  • WGC는 힙이 1개

  • SGC는 힙이 N개(=논리 코어 갯수), GC 쓰레드 N개. gcConcurrent 옵션이 켜져있는경우 BGC 쓰레드도 N개 생김.

  • 힙의 갯수가 많으므로 SGC가 메모리를 더 많이 확보한다. 단, 힙 1개당 크기는 환경에 따라 다르다.

  • SGC는 멀티코어에서만 가능하다. 싱글코어면 병렬처리가 불가능하므로 이점이 전혀없다.

WGC와 SGC를 세팅하는 방법은 config에서 다음과 같이 설정하면 끝이다.

1
<gcServer enabled="true"/>

Non-concurrent GC / Concurrent GC / Foreground GC / Background GC

참고: [MSDN] Background garbage collection

Non-concurrent GC: GC 수행시 스레드를 전부 멈추고(= 이걸 Stop The World (STW)라고 한다) GC만 수행

Concurrent GC: 백그라운드에서 2세대 GC작업을 최대한 진행하고 스레드가 멈추는 일을 줄이냐의 차이다.

Foreground GC: 백그라운드 GC수행시 임시세대(0, 1세대)가 부족해 GC를 수행되는 것.

Background GC: .NET 4.0부터 개선된 버전의 Concurrent GC. 기존 Concurrent는 2세대 GC 중 Foreground GC가 발생할 조건이되어도 백그라운드 GC가 완료될 때까지 블락시켰다. Backgound GC가 된 이후로 Foreground GC가 발생하면 정리중이던 Background를 잠깐 멈춰놓고 Foreground GC를 수행하도록 개선되었다.

  • Concurrent 기능은 2세대 GC를 위한 기능이다. 0/1 세대는 세팅이 어떻든간에 STW가 항상 발생한다.

  • .NET 4.5 부터 Concurrent GC는 Background GC로 변경되었다.

Background/Concurrent GC를 세팅하는 방법은 config에서 다음과 같이 설정하면 끝이다.

1
<gcConcurrent enabled="true"/>

GC 관련 참고하면 좋을 사이트

This post is licensed under CC BY 4.0 by the author.

몬테카를로 트리 탐색 - Monte-carlo Tree Search (MCTS)

.NET GC 정리(2)