| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 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 |
- 취업
- 게임 회사
- 유니티
- 붕괴스타레일
- 게임분석
- 후기
- LookAt
- 나만의 견해
- 공부
- 컴포넌트
- spritemask2d
- 뭐드라
- 내일배움캠프
- 스파르타내일배움캠프
- 취미
- 점프
- 코딩
- 프로그래밍
- 게임용어
- til
- 원신
- 붕괴 스타레일
- 까먹기전에메모
- spritelibrary
- 연습
- materialpropertyblock
- ag 내일배움캠프
- c#
- 스파르타내일배움캠프TIL
- 블렌더
- Today
- Total
덴바의 노트
내일배움캠프 12일차 TIL 본문

오늘의 키워드
- StackOverFlow 에러
오늘은 StackOverFlow에 대해서 알아보겠습니다.
StackOverFlow가 발생하는 이유는?
Stack 메모리에 호출 스택이 너무 많아서 메모리가 부족하게 되면서 발생하는 에러입니다.
그럼 여기서 Stack은 뭐고 왜 부족한 걸까?
StackOverFlow에 대해서 알려면 먼저 프로그램이 가지는 메모리 영역에 대해서 알아야 합니다.
메모리는 크게 4개의 영역으로 나뉩니다.

코드 영역 메모리
코드 영역 메모리는 말대로 스크립트에 작성된 코드들이 메모리로 들어갑니다.
데이터 메모리
데이터 메모리는 뭘까요?
총 2가지가 있습니다.
1. Static
ex) public static int count;
위 예시와 같이 static을 사용하게 되면 해당 데이터는 다름 아닌 데이터 메모리에 저장이 됩니다.
그럼 남은 한 가지는 뭘까요?
그것은 바로
2. 전역 변수
입니다.
전역 변수는 무엇일까요?
변수는 기본적으로 크게 2가지로 나뉩니다.
1. 전역 변수
public int count = 0;
...
2. 지역 변수
public void Test()
{
int index = 0;
for(int i = 0; i < 3; i++)
{
index++;
}
}
위의 코드를 보시면
전역 변수는 함수 또는 생성자 등을 제외한 Class 내에서 선언한 변수로
클래스 내 어디서든 참조가 가능합니다.
그렇기에 해당 클래스 내에서는 static과 비슷한 역할을 할 수 있으며,
해당 변수는 전역 변수로써 데이터 메모리에 저장됩니다.
...
하지만 지역 변수는 다릅니다.
지역 변수란 전역 변수와는 달리 함수 내에서 생성된 변수들로
선언 시 일시적으로 Stack 메모리에 저장이 된 후,
해당 함수에서 벗어나게 되면 메모리에서 사라집니다.
스택 메모리
그럼 스택 메모리는 뭘까요?
스택 메모리는 데이터가 Value Type일 경우 스택 메모리에 저장이 됩니다.
그럼 Value Type은 뭘까요?
한국어로 값 형식이라고 부르는 이 데이터는
주로 bool, byte, int, float, char, 그리고 enum과 struct로 정해져있습니다.
여기서 어? 왜 string은 포함이 안되지? 라고 생각하실 수 있지만
배열은 기본적으로 Reference Type이며 string은 문자열, 즉 char[]과 같기 때문입니다.
힙 메모리
그러면 힙 메모리에 저장되는 데이터들은 뭐가 있을까요?
1. Array
그렇습니다. 기본적으로 배열은 데이터를 0번의 주소를 저장하고
그 다음의 index값을 얻기 위해서는 1씩 주소값을 증가시키면서 참조하는 형식입니다.
2. New
바로 객체를 생성할 때 사용하는 new 키워드입니다.
Animal cat = new Cat();
위와 같이 new 키워드를 사용하면 해당 데이터는 Heap 데이터 영역에 저장이 됩니다.
단, Heap 영역으로 곧장 가는 것이 아닙니다.
Heap 영역의 데이터를 얻기 위해서는
먼저, Heap에 위치하는 데이터를 참조하기 위해서 Stack에 저장해둔 주소를 찾아갑니다.
그리고 해당 주소를 타고 이동해서 Heap에 있는 데이터를 참조하는 형식입니다.
그럼 여기서 StackOverFlow가 발생한 원인에 대해서 대표적인 하나를 예시로 들어보겠습니다.
그것은 바로 무한 루프로 빠지는 재귀 호출입니다.
public void GameStart()
{
Console.WriteLine("게임 시작");
GameStart();
}
위의 경우는 너무 눈에 띄게 보이는 형식이지만, 함수 내에 본인 함수를 다시 호출하면서,
마치 While문과 같이 무한으로 코드를 반복하게 됩니다.
이러한 형식의 코드가 작성이 되었다면, StackOverFlow 에러가 발생하게 됩니다.
하지만 실제로는 저렇게 티가 나게 작성되어있지는 않고
정말 교묘하게 재귀호출하지 않을 것이라고 생각했던 부분이 재귀 호출되게 구현되는 경우가 많습니다.
그런 문제점들을 해결하려면 어떻게 해야할까요?
그건 바로 객체 지향적인 코드를 잘 만들어야 합니다.
스크립트를 모듈화하여 응집도를 최대한 높이고,
각 모듈간의 결합도를 최대한으로 낮춰서 코드를 작성한다면
위와 같은 재귀 호출은 일어날 확률이 낮습니다.
하지만 그럼에도 재귀 호출 에러가 난다면 어떻게 해야할까요?
그런 경우에는 우선 에러가 나기 전 부분에 중단점을 찍고 F11을 눌러가면서
어느 부분에서 재귀 호출이 발생하는지 찾아야 합니다.
오늘의 회고
본인이 짠 코드에 재귀 호출에 걸리는 경우가 종종 발생하게 되었습니다.
특히 오늘 같은 경우는 Player() 생성자에
싱글톤에 구현된 GameManager의 EventManager의 기능을 이용하는 부분에서
StackOverFlow가 발생했습니다.
GameManager에서는 Player 또한 바로 접근할 수 있게 해뒀는데,
그 부분에서 재귀 호출이 발생하는 것으로 추정이 됐습니다.
결론적으로 정확히는 왜 재귀호출이 발생하는지 원인을 100% 모른채
Player의 생성자에 EventManager를 참조하는 부분을
Player에서 생성하는 PlayerData의 코드 부분에 넣는 것으로
재귀 호출은 피할 수 있었습니다.
하지만 깨달은 점은 GameManager에 Player를 넣은 부분은 큰 실수였다고 생각했습니다.
다음에 싱글톤을 구현한다면, 사운드, UI, SCENE, Pool 등
정말 전체적으로 기능상 필요한 부분만 넣어야겠다라는 생각이 들었습니다.

'프로그래밍 노트 > TIL' 카테고리의 다른 글
| 내일배움캠프 14일차 WIL (1) | 2024.05.03 |
|---|---|
| 내일배움캠프 13일차 TIL (0) | 2024.05.02 |
| 내일배움캠프 11일차 TIL (0) | 2024.04.30 |
| 내일배움캠프 10일차 TIL (0) | 2024.04.29 |
| 내일배움캠프 9일차 WIL (1) | 2024.04.26 |