Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
Tags
- 책 정리
- 정렬
- 해커랭크 문제풀이
- Unity
- 이펙티브 씨샵
- 독후감
- 해커랭크
- HackerRank
- 이펙티브 C#
- 자유여행
- 코토리
- IOS
- 알고리즘 문제풀이
- javascript
- 유니티
- C#
- 프로그래밍도서
- 알고리즘
- 프로그래밍
- 서평
- 일본음식
- 개발
- 빌드
- Android
- 문제풀이
- 독서
- 책리뷰
- Effective C#
- build
- 방학여행
Archives
- Today
- Total
Console.Log
[Effective C#] 2장 .NET 리소스 관리 ( ITEM 11 ~ 17 ) 본문
ITEM 11: .NET 리소스 관리에 대한 이해
- 힙에 관한 메모리 관리는 가비지 콜렉터가 완전히 책임진다. 그러나 그 외의 비관리 리소스는 개발자가 관리해야함.
→ 비관리 리소스는 finalizer 와 IDisposable인터페이스라는 두가지 메커니즘 제공
- [위험] finalizer: finalizer를 포함하고 있는 객체를 가비지로 판단한 경우, 이 객체에 대한 참조를 다른 큐에 삽입하여 나중에 finalizer를 호출될 수 있도록 사전 준비만 수행.
가비지 콜렉터의 세대 개념
- 0세대: 수집 절차 이후 생성된 객체들
- 1세대: 수집 절차에서 살아남은 객체들
- 2세대: 두번 혹은 그 이상의 수집 절차에서 살아남은 객체들
수집 절차
- 기본적으로 0세대 객체만 검사
- 1세대는 대략 10번에 한 번 검사
- 2세대는 대략 100번에 한 번 검사
결론
- 비관리 리소스를 해제하는 좋은 방법은 IDisposable을 사용하는 것이다.
ITEM 12: 할당 구문보다 맴버 초기화 구문이 좋다.
특징
- 새로운 생성자를 추가하더라도 별도로 초기화할 필요가 없다.
- 베이스 클래스 생성자가 호출되기 전에 멤버에 대한 초기화가 이루어진다.
사용법
1 2 3 4 | public class MyClass { private List<string> labels = new List<string>(); } | cs |
예외사항
- 만약 클래스내의 객체를 생성하는 방식이 여러가지라면 두 번 할당하는 꼴이 되므로 X
- C#은 저수준에서 모든 값을 0으로 초기화하기 때문에 0이나 null로 초기화는 X
- 예외 처리가 필요하다면 반드시 생성자 내에서 처리..!
ITEM 13: 정적 클래스 멤버를 올바르게 초기화하라
- 정적 멤버 변수를 포함하는 타입이 있다면 인스턴스를 생성하기 전에 반드시 정적 멤버 변수를 초기화 해야한다.
- 정적 멤버 초기화 구문
- 정적 생성자 : 타입 내에 정의된 모든 메서드, 변수, 속성에 최초로 접근하기 전에 자동으로 호출됨
정적 생성자를 이용하는 사례 ( ex: Singleton )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | // 정적 멤버를 간단히 초기화 하는 경우 public class MySingleton { private static readonly MySingleton theOneAndOnly = new MySingleton(); public static MySingleton TheOnly { return theOneAndOnly; } private MySingleton() { } } // 정적 생성자 버전 ( 초기화 과정이 더 복잡한 경우 ) public class MySingleton2 { private static readonly MySingleton2 theOneAndOnly; static MySingleton2() { theOneAndOnly = new MySingleton2(); } public static MySingleton2 TheOnly { get { return theOneAndOnly; } } private MySingleton2() { } } | cs |
ITEM 14: 초기화 코드가 중복되는 것을 최소화하라
-
공용생성자를 이용하라
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | public class MyClass { private List<int> coll; private string name; private float scale; public MyClass() : this(0.2f, 0, string.Empty) { } public MyClass(float scale, int initalCount = 0, string name = "") { coll = (initalCount > 0) ? new List<int>(initalCount) : new List<int>(); this.name = name; this.scale = scale; } } | cs |
-
초기화 과정 일부를 공용생성자에 위임할 수 있다.
-
어떠한 경우에도 제한 없이 new MyClass()를 사용할 수 있다.
-
베이스 클래스의 생성자가 반복적으로 호출 되는것도 막아줌
인스턴스가 생성될때 수행되는 과정
< 클래스 자체에 대한 초기화 작업은 한번만! >
- 정적 변수의 저장공간을 0으로 초기화
- 정적 변수에 대한 초기화 구문
- 베이스 클래스의 정적 생성자 수행
- 정적 생성자 수행
< 동일한 타입으로 추가 인스턴스 생성할경우 여기서 부터 반복 >
- 인스턴스 변수의 저장공간을 0으로 초기화
- 인스턴스 변수에 대한 초기화 구문 수행
- 적절한 베이스 클래스의 인스턴스 생성자 수행
- 인스턴스 생성자 수행
ITEM 15: 불필요한 객체를 만들지 말라
-
자주 객체를 생성하는 지역변수를 멤버변수로 변경하는 방법 ( 참조 타입만 )
-
자주 사용되는 참조타입의 인스턴스를 정적 멤버 변수로 선언하는 방법
- 단점1: 경우에 따라서 메모리상에 필요이상으로 남을수 있음
- 단점2: Dispose() 메서드를 호출해야 할 시점을 결정할 수 없음.
- 사용법
- 1234567891011private static Brush blackBrush;public static Brush Black{get{if(blackBrush == null)blackBrush = new SolidBrush(Color.Black);return blackBrush;}}
cs
-
변경 불가능한 타입(Immutable) 부분 ( ex_ string.. )
- string은 변경할 수 있는것처럼 보이나 새로운 stirng 객체가 생성됨
→ string.Format, 문자열 보간, StringBuilder등 사용하기
- 결론: 변경 불가능한 타입을 작성하는 경우 StringBuilder와 같은 Builder 기능을 함께 제공하는것을 고려해보기.
ITEM 16: 생성자 내에서는 절대로 가상 함수를 호출하지 말라
- 객체가 완전히 생성되기전 가상 함수를 호출하면 이상 동작이 발생함.
- 베이스 클래스의 생성자 내에서 가상 함후를 호출하면 파생 클래스가 가상 함수를 어떻게 구현했는지에 따라 매우 민감하게 동작하게됨.
- FxCop나 정적 코드 분석기등을 통해 이런 코드 패턴을 쉽게 발견 할 수 있음.
ITEM 17: 표준 Dispose 패턴을 구현하라
- 비관리 리소스를 포함하고 있다면 무조건 finalizer를 구현하라.
- 반대로 비관리 리소스가 없을 경우, finalizer를 절대로 추가하지 마라.
- Dispose 메서드 내에서는 리소스 정리작업만 수행하라.
표준 Dispose 패턴 구현
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | public class MyResourceHog : IDisposable { private bool alreadyDisposed = false; ~MyResourceHog() { // Dispose가 호출 되지 않은 상황인 경우에 finalizer 로 들어옴 // 비관리 리소스가 포함된 경우나 // IDisposable을 구현한 다른 타입을 포함해야 할 경우에만 구현. Dispose(false); } public void Dispose() { Dispose(true); // GC가 돌때 fionalizer를 호출하지 않도록 GC.SuppressFinalize(this); } protected virtual void Dispose(bool isDisposing) { if (alreadyDisposed) return; if(isDisposing) { // 관리 리소스 정리 } // 비관리 리소스 정리 // dispose Flag alreadyDisposed = true; } public void ExampleMethod() { if(alreadyDisposed) throw new ObjectDisposedException("MyResourceHog", "Called Example Method on Disposed object"); } } public class DerivedResourceHog : MyResourceHog { private bool disposed = false; protected override void Dispose(bool isDisposing) { if (disposed) return; if(isDisposing) { // 관리 리소스 정리 } // 비관리 리소스 정리 // 베이스 클래스가 자신의 리소스 정리할 수 있도록 base.Dispose(isDisposing); disposed = true; } } | cs |
'프로그래밍 > Effective C#' 카테고리의 다른 글
[Effective C#] 1장 C# 언어 요소 정리 ( ITEM 1 ~ 10 ) (0) | 2019.05.03 |
---|