Static 이란?
클래스나 배열 같은 경우, 힙 메모리에 할당되기 때문에 프로그램 실행 중에도 상황에 따라 저장된 위치가 내부적으로 바뀌는 동적인 모습을 보인다.
반대로 메모리 영역을 고정적으로 차지했으면 좋겠다?
이 때 사용할 수 있는게 정적인 영역인 static이다.
전역 카운터, 캐시, 유틸리티 함수 등 공유 상태가 필요할 때 객체를 만들지 않고 타입 차원에서 접근하는 방법이다.
잘 쓰면 편리하지만 타입이 처음 사용되는 순간 메모리에 할당되어 프로그램이 종료되기 전까지 계속 유지되기 때문에 주의해서 사용하지 않으면 메모리 해제 측면의 문제가 발생할 수 있다.
static 참조가 객체를 물고있는 동안에는 GC가 수거하지 못하기 때문에 이벤트 구독 / 캐시 누수에 주의가 필요하다.
Static 원리
앞서 말한 것처럼 static을 붙인 필드, 메서드, 프로퍼티는 객체 단위가 아니라 클래스 단위에서 공유되는 멤버가 된다.
즉, 인스턴스를 몇 개를 만들든 해당 값은 오직 한 번만 메모리에 할당되고 모든 객체가 이를 참조하게 된다.
React의 Context와 비슷하다는 생각이 바로 들었다.
Static 필드
class Hunter
{
public static int _deathCount; // 모든 Hunter가 공유
public int _healthPoint;
public int _money;
}
이런 필드값을 갖고있는 Hunter라는 클래스가 있다고 가정해보자.
여기의 필드값은 new Hunter을 통해 생성한 인스턴스가 각각 고유하게 보유하고 있는 고유값이 된다.
하지만 만약에, 레이드 도중에 모든 Hunter 파티원들이 _deathCount를 공유해서 일정 이상 사망하면 더 이상 부활하지 못하는 시스템을 만들고 싶은 경우에 귀찮은 일이 발생한다.
_deathCount를 관리하는 외부의 전역변수가 필요해진다.
이때 static을 통해 _deathCount 필드를 정적인 전역 변수로 만들면 모든 Hunter 들이 이 값을 공유할 수 있게 될 것이다.
이렇게 정적 필드가 된 필드값은 접근 방식도 달라진다.
Hunter h1 = new Hunter();
h1._deathCount += 1; // 불가능
Hunter._deathCount += 1; // 이렇게 클래스명으로 바로 접근해야함
Static 메서드
정적 메서드는 앞의 정적 필드처럼 인스턴스가 없어도 바로 실행할 수 있다.
class MathHelper
{
public static int Double(int x)
{
return x * 2;
}
}
int result = MathHelper.Double(5); // 객체 생성 없이 바로 호출
정적 메서드는 일반 필드와 상호작용할 수 없다.
그 이유는 정적 메서드는 전역에 존재하기 때문에 특정 인스턴스에 존재해야할 일반 필드가 도대체 어떤 인스턴스의 필드값인지 알 수 없기 때문이다.
그런데 어디서 많이 본 모양이지 않나?
우리가 늘 자주 쓰고있는 Console.WriteLine() 또한 객체 생성 없이 바로 호출할 수 있다.
Random은 객체 생성이 필요한데 말이다.
퍼즐이 맞춰져 가고 있다!!
Static 프로퍼티
필드, 메서드에 사용할 수 있다면 프로퍼티에도 당연히 사용할 수 있다.
class GameManager
{
private static int _score;
public static int Score
{
get { return _score; }
set { _score = value; }
}
}
// 어디서든 접근 가능
GameManager.Score = 100;
Console.WriteLine(GameManager.Score); // 100
Static 클래스
클래스 자체에도 통째로 static으로 선언할 수 있다.
이 경우 인스턴스를 만들 수 없고, 내부의 모든 필드와 메서드는 static이어야만 한다.
static class myMath // 정적 클래스
{
//int a; // 바로 에러남
static int a; // static 계열들만 쓸 수 있음
static int b;
const string sangsu = "응 나는 상수. 정적 클래스에서 사용 쌉가능.";
//void SetNum() // static 이 아닌 메서드는 바로 에러남
public static int DoubleTheNumber(int toDouble)
{
return toDouble * 2;
}
}
상수는 한 프로그램 안에서 변하지 않는 값이기 때문에 사용할 수 있다.
Static 생성자
정적 생성자는 클래스가 처음 사용될 때 한 번만 실행된다.
using System;
namespace Static
{
static class myMath
{
static myMath()
{
Console.WriteLine("나 생성. 스태틱 생성자");
}
public static void doSomething()
{
Console.WriteLine("뭐라도 해");
}
}
class Program
{
static void Main(string[] args)
{
myMath.doSomething();
myMath.doSomething();
myMath.doSomething();
myMath.doSomething();
}
}
}
// 나 생성
// 뭐라도 해 - 4번 출력
이런 식으로 말이다.
주로 정적 필드 초기화에 사용한다고 하는데
실제로 어떤 상황에서 사용될지...?
Static의 장단점
장점
- 객체를 만들지 않아도 바로 접근 가능한 편리함
- 모든 인스턴스에서 공유하는 전역 상태 관리에 유리
- 유틸리티 함수, 상수 모음, 전역 카운터 등에 적합
단점
- 프로그램이 끝날 때까지 메모리에 유지되어 불필요한 낭비나 메모리 누수 등의 위험이 있음
- 남용하면 객체지향적 설계가 무너짐
추가로 스태틱은 클래스와는 별도로 실행 순간 스태틱 전용 메모리 공간에 따로 배치된다고 한다.
'C#' 카테고리의 다른 글
| C# - 클래스 Static 실습 문제 풀이 (0) | 2025.09.19 |
|---|---|
| C# - 클래스 상속 (Inheritance) (0) | 2025.09.19 |
| C# - 클래스와 구조체의 차이 (0) | 2025.09.17 |
| C# - 메모리와 가비지 컬렉터 (GC) (0) | 2025.09.17 |
| C# - 클래스 실습 문제 풀이 (생성자) (0) | 2025.09.17 |