내용 보기
작성자
관리자 (IP : 172.17.0.1)
날짜
2022-03-22 09:16
제목
[C#] 다시 한번 기초 다지기! - GC(가비지 컬렉션)
Garbage Collection *GC 스레드는 왜 단일 스레드일까? 오버헤드를 줄이자!
CLR이 초기화되면 '0세대'의 크기 결정. 이 시점에 CLR은 '1세대' 크기도 함께 결정되며 '0세대' 컬렉션만 수행. 0세대와 1세대를 기준으로 계속해서 Managed Heap을 사용하게 되면 언젠가는 1세대의 크기가 점점 커져서 한계점에 도달하게 됨. GC는 스스로 성능 최적화가 가능하다 GC가 수집을 할 때마다 만들어진 프로세스의 동작 방식을 학습한다. 메모리를 생각한다면 Heap보다 Stack! Value Type은 스택에 저장, Reference Type은 힙에 저장 ex) class와 struct 정의 예시 public class Book
{
public decimal price;
public string title;
public string author;
} public struct Book
{
public decimal price;
public string title;
public string author;
}
약한 참조로 가비지화 시키자! 의도하지 않은 참조 없애기 public class Sample
{
private class Fruit
{
public Fruit(string name)
{
this.Name = name;
}
public string Name
{
private set;
get;
}
}
public static void TestWeakRef()
{
Fruit apple = new Fruit("Apple");
Fruit orange = new Fruit("Orange");
Fruit fruit1 = apple; // 강한 참조
// WeakReference를 이용
WeakReference fruit2 = new WeakReference(orange);
Fruit target;
target = fruit2.Target as Fruit;
// 이 경우 결과는 애플과 오렌지가 나오게 됩니다.
Console.WriteLine(" (1) Fruit1 = \"{0}\", Fruit2 = \"{1}\"",
fruit1.Name, target == null ? "" : target.Name);
// 모두 참조하지 않도록 null값을 넣어줍니다.
apple = null;
orange = null;
// 가비지 컬렉터를 작동시킨다
System.GC.Collect(0, GCCollectionMode.Forced);
System.GC.WaitForFullGCComplete();
// 그 후 같은 방법으로 결과를 확인해보면
// fruit1과 fruit2의 값을 바꾼 적은 없지만, fruit2의 결과가 달라집니다.
target = fruit2.Target as Fruit;
// 결과는 애플만 나오게 된다.
// 오렌지는 가비지 컬렉터에게 회수되버렸기때문입니다
Console.WriteLine(" (2) Fruit1 = \"{0}\", Fruit2 = \"{1}\"",
fruit1 == null ? "" : fruit1.Name,
target == null ? "" : target.Name);
}
} Fruit2가 참조하고 있던 orange 인스턴스는 가비지 컬렉터에 의해 회수돼 null이 됨. Disposable 원하는 시점에 메모리 해제! MS는 관리되지 않는 메모리(리소스)를 해제하는 용도로 System.IDisposable이라는 인터페이스를 제공한다. using (Font font1 = new Font("Arial", 10.0f))
{
byte charset = font1.GdiCharSet;
} {
Font font1 = new Font("Arial", 10.0f);
try
{
byte charset = font1.GdiCharSet;
}
finally
{
if (font1 != null)
((IDisposable)font1).Dispose();
}
}
<리스트 8> Generic collection
class Example
{
static public void BadCase()
{
ArrayList list = new ArrayList();
int evenSum = 0;
int oddSum = 0;
for (int i = 0; i < 1000000; i++)
list.Add(i);
foreach (object item in list)
{
if (item is int)
{
int num = (int)item;
if(num % 2 ==0) evenSum += num;
else oddSum += num;
}
}
Console.WriteLine("EvenSum={0}, OddSum={1}", evenSum, oddSum);
}
static public void GoodCase()
{
List<int> list = new List<int>();
int evenSum = 0;
int oddSum = 0;
for (int i = 0; i < 1000000; i++)
list.Add(i);
foreach (int num in list)
{
if (num % 2 == 0) evenSum += num;
else oddSum += num;
}
Console.WriteLine("EvenSum={0}, OddSum={1}", evenSum, oddSum);
}
} 2. 너무 큰 객체 할당을 피할 것. |
출처1
https://blog.naver.com/sam_sist/220991901842
출처2