TIL: 인터페이스와 가비지 컬렉터 개념 정리
인터페이스란 무엇인가?
- 인터페이스는 클래스가 반드시 구현해야 하는 메서드와 속성의 계약을 정의하는 기능임.
- 이를 통해 코드의 구조를 명확하게 하고 일관성을 유지할 수 있음.
- 인터페이스 자체는 구현을 가지지 않으며, 클래스가 이를 상속받아 실제 기능을 구현해야 함.
주요 특징:
- 다중 상속이 가능함
- 메서드의 시그니처(이름, 반환값, 파라미터)만 정의됨
- 다른 클래스들이 동일한 인터페이스를 구현할 수 있어 유연한 설계 가능함
예시 코드:
public interface IAttackable
{
void Attack();
}
public class Player : IAttackable
{
public void Attack()
{
Console.WriteLine("Player is attacking!");
}
}
코드 설명:
- IAttackable은 Attack 메서드를 정의한 인터페이스임.
- Player 클래스는 이 인터페이스를 구현하여 Attack 메서드를 실제로 정의함.
인터페이스와 추상 클래스의 차이
- 인터페이스와 추상 클래스 모두 추상적인 개념을 정의하지만 차이점이 존재함.
구분 인터페이스 추상 클래스
구현 여부 | 메서드의 구현 없음 | 일부 메서드 구현 가능 |
다중 상속 | 다중 구현 가능 | 단일 상속만 가능 |
필드(변수) 포함 | 불가능 | 가능 |
접근 제어자 | 모든 메서드는 기본적으로 public | 접근 제어자 지정 가능 |
목적 | 기능의 계약 | 공통 기능의 일부 구현 제공 |
간단한 예시:
// 인터페이스
public interface IRun
{
void Run();
}
// 추상 클래스
public abstract class Animal
{
public abstract void Eat();
public void Sleep()
{
Console.WriteLine("Sleeping...");
}
}
가비지 컬렉터란 무엇인가?
- **가비지 컬렉터(Garbage Collector, GC)**는 프로그램이 더 이상 필요하지 않은 메모리 자원을 자동으로 해제하는 역할을 함.
- 개발자가 수동으로 메모리를 관리할 필요 없이, 불필요한 객체를 찾아 제거함으로써 메모리 누수를 방지함.
작동 원리:
- 프로그램 실행 중 객체의 참조 여부를 검사함.
- 참조되지 않는 객체를 탐지하여 메모리에서 해제함.
- 가비지 컬렉터의 장점과 단점
- 장점:
- 메모리 관리의 자동화로 개발자의 부담 감소
- 메모리 누수와 같은 오류 방지
- 코드의 유지보수가 쉬워짐
- 단점:
- GC가 실행될 때 성능 저하가 발생할 수 있음
- 메모리 해제 시점을 개발자가 제어할 수 없음
- 큰 객체를 다룰 때 오버헤드가 발생할 수 있음
가비지 컬렉터의 세대 개념
- 가비지 컬렉터는 객체를 세대(Generation)로 나누어 관리함.
- 각 세대는 객체의 수명에 따라 구분되며, 불필요한 메모리 회수를 효율적으로 수행함.
세대 설명
0세대 | 새로 생성된 객체가 위치하는 영역 |
1세대 | 0세대에서 생존한 객체들이 위치하는 영역 |
2세대 | 장시간 동안 참조되는 객체가 위치하는 영역 |
세대 관리 원리:
- 객체는 처음에 0세대에 할당됨.
- 0세대 GC 실행 후 살아남은 객체는 1세대로 승격됨.
- 1세대에서도 살아남으면 2세대로 이동함.
- 2세대 GC는 가장 비용이 많이 들며, 상대적으로 덜 자주 실행됨.
- 박싱과 언박싱 사용 시 주의할 점
- 박싱(Boxing): 값 형식을 참조 형식으로 변환하는 과정
- 언박싱(Unboxing): 참조 형식을 값 형식으로 변환하는 과정
주의할 점:
- 성능 저하: 박싱과 언박싱은 메모리 할당 및 복사를 유발하므로 성능에 영향을 줄 수 있음.
- 타입 일치: 언박싱 시 원래 타입과 일치하지 않으면 오류가 발생함.
- 불필요한 박싱 방지: 컬렉션 사용 시 제네릭을 활용하면 불필요한 박싱을 줄일 수 있음.
예시 코드:
int value = 10;
object boxed = value; // 박싱
int unboxed = (int)boxed; // 언박싱
- 제네릭이란 무엇인가?
- **제네릭(Generics)**은 데이터 타입을 일반화하여 코드의 재사용성을 높이는 기능임.
- 컬렉션이나 메서드에서 다양한 타입을 다룰 때, 타입 안전성과 성능을 보장할 수 있음.
장점:
- 타입 안전성: 잘못된 타입의 데이터를 컴파일 단계에서 방지함.
- 성능 개선: 박싱/언박싱을 줄여 성능을 높임.
- 코드 재사용: 여러 타입에 대해 하나의 코드로 대응 가능함.
예시 코드:
public class GenericExample<T>
{
private T data;
public void SetData(T value)
{
data = value;
}
public T GetData()
{
return data;
}
}
// 사용
GenericExample<int> intExample = new GenericExample<int>();
intExample.SetData(5);
Console.WriteLine(intExample.GetData());
설명:
- T는 제네릭 타입 파라미터로, 실행 시점에 실제 타입으로 대체됨.
- GenericExample 클래스는 어떤 데이터 타입이든 처리할 수 있음.
주의사항:
- 제네릭은 값 형식과 참조 형식 모두 사용할 수 있음.
- 제네릭 메서드를 구현할 때 타입 제약 조건을 사용할 수 있음.
요약
- 인터페이스: 메서드 시그니처를 정의하는 계약으로 다중 상속 가능
- 추상 클래스와 차이점: 구현 여부, 필드 포함, 단일 상속 여부 등
- 가비지 컬렉터: 메모리 자동 관리 도구, 장점과 단점 존재
- 세대 개념: 0세대, 1세대, 2세대로 객체를 나눠 GC 효율화
- 박싱과 언박싱: 성능 저하 주의, 제네릭으로 방지 가능
- 제네릭: 타입 안전성과 코드 재사용성을 높이는 기능