-
우수 답변
4. struct와 class를 비교해서 설명해주세요.
★값 타입, 참조 타입, 메모리 영역
+상속 가능 여부, 함수 선언 여부 필요
struct와 class의 차이점에 대한 질문은 너무나도 많이 나오기 때문에 관련 공부를 하신분들이라면 너무나도 쉽게 답변이 가능합니다.
C#과 Unity 생태계에서 메모리의 어떤 영역을 활용하고 힙 메모리가 사용 된다면 GC와는 어떤 연관이 있는지 까지 확장하여 설명할 수 있으면 남들과 차이점을 보여줄 수 있을겁니다.
struct와 class의 가장 큰 차이점이라고 한다면 struct는 값 타입 class는 참조 타입이라는 것입니다.값 타입은 스택메모리에 참조 타입은 힙 메모리에 저장되게 되는데 C#의 특성상 힙에 할당된 메모리는 가비지 컬렉터가 사용하지 않는 메모리를 정리해줍니다. 이때 처리해야할 양이 많으면 프로그램의 동작 속도가 느려지기 때문에 구조가 간단하고 가벼운 것들이라면 struct를 사용하는게 좋습니다. 스택에 할당된 메모리는 사용 후 바로 종료되기 때문에 가비지 컬렉션이 발생하지 않기 때문이죠하지만 struct도 단점이 있는데요. struct 내에 변수가 많아지게 된다면 크기가 제한적인 스택에 저장된 struct의 특성상 스택 오버플로우가 발생할 수도 있습니다.
가장 큰 차이점은 struct는 스택메모리에 저장되는 값 타입, class는 힙 메모리에 저장되는 참조 타입이라는 것 입니다.
C#의 특성상 힙에 할당되는 메모리 중에서 사용하지 않는 메모리는 가비지 컬렉터가 정리해줍니다. 이때, 처리해야하는 양이 많으면 프로그램의 동작 속도가 느려지게 됩니다.
스택에 할당되는 메모리는 사용 후 바로 종료되기 때문에 가비지 컬렉션이 발생되지 않으므로 구조가 간단하고 가벼운 것이라면 struct를 사용하는 것이 좋습니다.
단, struct 내에 변수가 많아지게 된다면 크기가 제한적인 스택의 특성으로 인하여 스택 오버플로우가 발생할 수 있습니다.
5. 가비지 컬렉터에 대해 설명해주세요.
관리 되는 힙, GC 스파이크는 왜 발생할까? GC를 최적화 하는 방법
GC는 생각보다 종류가 많습니다. Unity에서는 어떤 GC를 사용하고 그들의 동작을 알아두면 좋습니다. 또한, GC하면 뺴놓을 수 없는 GC 스파이크라는 키워드도 같이 공부해 두면 좋습니다. GC가 호출 될 때 어떠한 영향이 있는지 게임을 플레이하다 어떤 문제가 발생 할 수 있는지 등과 이를 최적화 하는 방법이 있는지를 같이 공부하면 좋습니다. Unity 공식 도큐먼트에 있습니다.
메모리의 관리 방법 중에 하나입니다. 프로그래머가 메모리를 할당한 후 해제를 안 하여 생기는 버그를 해결하기 위해 가비지 컬렉션이라는 시스템이 내장되었습니다. 가비지 컬렉션은 시스템에서 더 이상 사용하지 않는 동적 할당된 메모리 블럭을 찾아 자동으로 다시 사용 가능한 자원으로 회수하는데 이 과정에서 회수해야하는 자원을 모으는 역할을 수행하는 부분을 가비지 컬렉터라고 합니다. 이런 가비지 컬렉터는 메모리 할당 / 사용 중인 메모리 인식 / 사용하지 않는 메모리 인식 와 같은 역할을 수행합니다
메모리 관리 방법 중 하나로 메모리를 할당한 후에 해제를 하지 않아서 생기는 버그를 해결해줍니다.
가비지 컬렉터는 시스템에서 더 이상 사용하지 않는 동적 할당된 메모리를 찾아 다시 사용 가능하도록 회수되어야하는 자원을 모으는 역할을 수행합니다.
가비지 컬렉터가 자원(메모리)를 모을 때 기존 메모리 정리 작업도 같이하게 됩니다. 이 때, Unity Profiler를 볼 때 한 번씩 튀는 현상이 나타나는데 그것을 스파이크라고 합니다. 스파이크가 생기게 된다면 플레이 화면이 느려진다는 것을 의미합니다.
이유는 메모리 사용량이 한계에 다다르면 정리를 해야하므로 가비지 컬렉터를 부르게 됩니다. 뿐만 아니라 구동하고 있는 환경이나 플랫폼, GC 할당 빈도 등 다양한 요소가 가비지 컬렉터를 부르게 되면서 느려지고 스파이크 현상이 나타나게 됩니다.
6. 가비지 컬렉터를 회피하기 위한 전략은 무엇이 있나요?
가비지에 대한 핵심 키워드는 메모리, 참조/값 형식입니다.
참조타입과 값타입이 어떻게 돌아가면 이때 참조가 남은 부분이 가비지로 돌아가니 참조를 줄이면 됩니다. 다만 실무를 하다보면 너무 복잡하지 않은 코드라면 크게 문제가 되지 않고 이게 문제가 될정도면 메모리 문제가 아니라 객체지향에 대한 이해가 부족한 상태입니다. 따라서 핵심적으로 문제가 될 부분들을 유의하면서 참조와 값타입을 상황에 맞게 사용해나가면 됩니다
1. 오브젝트 생성, 파괴보다 풀링을 사용한다.
2. 문자열을 더할 때는 스트링빌더를 사용한다.
3. Update처럼 반복되는 동작을 수행하는 곳에 New나 새로운 객체의 생성을 하지 않는다.
4. 사용하지 않는 객체를 직접 해제한다.반복되는 동작을 수행하는 곳에서 New 또는 새로운 객체를 생성하지 않거나 사용하지 않는 객체를 직접 해제합니다. 자주 사용하는 개체는 해제하는 것보다는 재사용하는 것이 좋으므로 오브젝트 풀을 사용해줍니다.
가비지 컬렉터를 사용해야하는 경우에는 원하는 타이밍에 가비지 컬렉터를 미리 호출할 수 있습니다. 가비지 컬렉터가 예상하지 못하는 곳에서 나타나서 스파이크를 만들어내는 것보다는 씬, UI 전환, 특정 이벤트 등 로딩이 있을 경우에 불러와서 처리 시켜주는 것이 좋습니다.
7. 가비지 컬렉션이란 무엇인지 설명해주세요.
가비지 콜렉터는 누수되는 메모리를 관리하기 위해 사용하지 않는 데이터를 자동으로 수거해줍니다. 이떄 가비지 콜렉터 자체에 대해 서술하는 것보다는 이로 인해 주의하는 점을 앞세워서 정리하는게 좋습니다. 가비지 콜렉터에 대한 질문이 있다면 어떤것이다- 라고 얘기하고 끝나는게 아니라 어떻게 대처해야하는지(6번문제) 같이 대답해주세요.
가비지 컬렉션은 더 이상 참조되지 않은 객체를 해제하여 메모리 누수를 방지하는 프로세스입니다. 모든 메모리를 순회하는 것보다 효율적인 관리를 위해 3세대의 힙 메모리로 나뉘어 관리되는데, 새로 만든 개체는 0세대 메모리에 할당되며 이것이 넘치게 되면 가비지 컬렉션이 일어나고 아직 참조되고 있는 객체들(라이브 객체들)은 오래된 순서대로 1세대 -> 2세대로 승격되는데 2세대로 갈 수록 할당되는 메모리가 커지게 됩니다. 만약 2세대 메모리도 넘치게 된다면 모든 세대에 대한 기비지 컬렉션이 실행되게 됩니다. 이때는 프로그램이 멈추며 가비지 컬렉션이 진행되기 때문에 이러한 일이 일어나지 않도록 유의해야 합니다.
가비지 컬랙션의 과정은 크게 3가지 주기를 통해 이루어지며루트 목록을 돌며 각 루트가 참조하는 것을 마킹하여 라이브 객체 목록을 생성하는 표시 단계(Marking)이러한 루트 목록에서 도달할 수 없는(사용되고 있지 않는) 객체를 가비지로 간주하여 비어 있는 공간으로 취급되도록 만드는 재배치 단계(Relocating)힙 영역을 순회하며 비어 있는 가비지의 공간에 도달 가능한 라이브 객체로 메모리를 덮어 씌우고 조정하는 압축 단계(Compacting)로 이루어져 있습니다.
7번은 너무 이론적인? 달달달 외워야하는 것이라서 정리를 하지 않았습니다.