현 블로그는 모바일 환경이 아닌 PC환경에 최적화 되어있습니다.

 Mir의 운영환경

 본체

 DeskTop

 O S

 Windows 7 Ultimate K

 Application

 VisualStudio2015

 .Net

 Framework Ver 4.0

메모리 관리 기법 (WeakReference)


WeakReference Class를 사용하여 메모리를 관리해보자. 


C#의 가장 큰 특징중 하나는 가비지 컬렉터(Garbage Collector)자동으로 메모리를 관리해준다는 것입니다.

상식적으로 가비지 컬렉터가 작동된다면 사용하지 않은 메모리는 자동으로 반환해야되지만

실제로 메모리가 반환되지 않고 계속 늘어나기도 합니다.


계속 늘어나는 메모리를 해제하고 싶지만 C#에는 따로 메모리를 해제하는 명령어가 없어서 메모리 릭(Memory leak)이 발생하기도 합니다.


이렇게 메모리가 계속 늘어나는 이유가 뭘까요?


가비지(Garbage)는 더 이상 참조가 없는 메모리를 뜻합니다.

메모리가 반환되지 않고 계속 늘어나고 있다면 어디선가 반환되야될 메모리를 의도치 않게 참조 하고 있어서 

가바지 컬렉터가 반환메모리로 인식하지 않아 청소를 못하고 자꾸 쌓이고만 있는것입니다.


저 또한 겪었던 문제로


하나의 UserControl을 만들었습니다.

이 UserControl은 DB에서 Select문으로 데이터를 끌어올때마다 생성하여 UserControl내부 로직을 타고 화면에 뿌려줍니다.

그 후 사용이 끝난 UserControl은 Dispose()를 해주지만 이상하게 검색을 할때마다 메모리가 늘어납니다.

결국 메모리 릭(Memory leak)이 발생하더군요.

저는 분명 모든 리소스를 해제했다고 생각하고 있었지만 어디선가 참조가 되고 있었는것이죠.

(결국 문제점을 발견하지 못했습니다. ㅠㅠ Garbage 강제 콜을 해도 메모리가 2%늘었다 1%줄었다 반복하더니 메모리 릭이 발생하더군요.)


이럴때 WeakReference Class를 사용해주면 됬었지만! 

그때 당시 저는 이 방법을 몰라서 한참을 돌아돌아 프로그램을 완성했었습니다.

(어찌했는지 기억도 잘 안나네요 ㅠㅠ)


WeakReference는 가바지 수집에 의한 개체 회수를 허용하면서 개체를 참조하는 일명 약한 참조를 만들어 냅니다.


아래 예제 소스를 보면서 설명하겠습니다.

(예제소스를 실행해보고 싶으시면 라벨 두개와 버튼 하나를 만들어서 복사후 연결만 시켜주면됩니다.)


using System; using System.Windows.Forms; namespace WeakReferenceTest { public partial class WeakReference_Form : Form { stock phone; stock notebook; stock stock1; WeakReference stock2; public WeakReference_Form() { InitializeComponent(); //Stock라는 클래스를 만들어 각각 Phone, NoteBook라는 물품을 담게 하였습니다. phone = new stock("Phone"); notebook = new stock("NoteBook"); //각각 참조를 거는데 phone은 일반적으로 사용하는 강한참조 //notebook은 WeakReference를 이용한 약한 참조를 걸어보도록 하겠습니다. stock1 = phone; stock2 = new WeakReference(notebook); //각각 라벨에 출력해보겠습니다. labelControl1.Text = stock1 == null ? "null" : stock1.name; labelControl2.Text = stock2.Target == null ? "null" : (stock2.Target as stock).name; //당연한 이야기겠지만 //------------ label1 = Phone //------------ label2 = NoteBook //가 출력됩니다. } private void button1_Click(object sender, EventArgs e) { //버튼 클릭시 phone과 notebook에 null을 넣어 초기화 시켜줍니다. phone = null; notebook = null; //가바지 컬렉터를 강제로 작동시켜보겠습니다. System.GC.Collect(0, GCCollectionMode.Forced); System.GC.WaitForFullGCComplete(); //다시한번 참조한 값을 각각 라벨에 출력해보겠습니다. labelControl1.Text = stock1 == null ? "null" : stock1.name; labelControl2.Text = stock2.Target == null ? "null" : (stock2.Target as stock).name; //어떻게 나올지 예상하셨나요? //필자는 stock1과 stock2 모두 참조 객체가 null로 변경이 되었으니 null이 출력된다고 생각했습니다. //하지만 결과는 //---------- label1 = Phone //---------- label2 = null //과 같이 출력됩니다. //강한참조는 참조 객체를 초기화 시켜도 Data를 붙잡고 있어서 메모리 회수가 안되는 것입니다. } } public class stock { public string name = ""; public stock(string name) { this.name = name; } } }


C#은 메모리를 컨트롤 안해도 된다는 생각을 가지고 있었지만 (필자가 배울때는 그렇게 배워서 ㅠㅠ)

실제로는 C나 C++만큼은 아니지만 메모리 관리를 해야된다고 생각합니다.


 

※ 관련글


+ Recent posts