기술나눔

게임 개발 인터뷰 질문 7

2024-07-08

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

기본 ArrayList 데이터 구조는 어떤 모습인가요?

ArrayList의 하위 레이어는 배열을 기반으로 구현됩니다. 이는 배열의 크기를 동적으로 확장하거나 축소하여 수행됩니다. 용량이 충분하지 않으면 더 큰 배열을 만든 다음 원본 데이터를 복사하고 마지막으로 새 데이터를 추가합니다.

ArrayList 확장 메커니즘은 다음과 같습니다. 첫 번째 요소가 추가되면 ArrayList의 용량은 새 요소가 추가될 때마다 10입니다. 용량을 초과하면 원래 용량이 두 배가 됩니다. 즉, 원래 용량 * 2입니다. , 원래 용량이 0이면 새 용량은 1입니다.

ArrayList 확장 메커니즘의 장점과 단점:

이점:
  1. ArrayList 확장 메커니즘은 이해하기 쉽고 구현하기 쉽습니다.
  2. 확장된 용량은 원래 용량보다 커야 합니다. 이렇게 하면 새 요소를 추가할 때 배열 복사본 수를 줄이고 요소 추가 효율성을 높일 수 있습니다.
결점:
  1. ArrayList 확장 메커니즘은 메모리 낭비를 초래하고 메모리 공간 낭비를 쉽게 일으킬 수 있습니다.
  2. 용량이 크면 확장할 때마다 많은 양의 메모리와 CPU 리소스가 필요하므로 성능에 영향을 미치므로 ArrayList를 사용할 경우 초기 용량을 적절하게 설정해야 합니다.
ArrayList는 스레드로부터 안전하지 않습니다.

ArrayList의 내부 구현은 배열을 기반으로 합니다. 여러 스레드가 동일한 ArrayList에 동시에 액세스하면 데이터 불일치가 발생할 수 있습니다. 예를 들어 한 스레드가 ArrayList의 데이터를 읽고 있고 다른 스레드가 데이터를 추가/삭제하는 경우입니다. ArrayList의 데이터를 변경하면 ArrayList 데이터를 읽는 스레드가 잘못된 데이터를 읽어 프로그램 오류가 발생할 수 있습니다.

ArrayList 스레드 불안정성을 해결하는 일반적인 방법은 다음과 같습니다.
  1. ArrayList 대신 Vector 사용: Vector는 동기화되고 모든 메서드는 동기화로 수정되므로 스레드로부터 안전합니다.
  2. ArrayList를 스레드 안전성으로 래핑: Collections.synchronizedList(list) 메서드를 사용하여 ArrayList를 스레드 안전성으로 변환합니다.
  3. CopyOnWriteArrayList 사용: 스레드로부터 안전하고 효율적인 컬렉션입니다. 쓰기 작업은 기본 배열을 복사하여 구현됩니다. 이 구현 비용은 읽기가 많고 쓰기가 적은 동시 시나리오에 적합합니다.
  4. 잠금을 사용하여 스레드 안전성 확보: ReentrantLock과 같은 잠금 메커니즘을 사용하여 스레드로부터 안전한 ArrayList를 구현할 수 있습니다.

스택과 힙의 차이점

  • 스택은 선입선출(First In Last Out) 후입선출(Last In First Out) 원칙에 따라 한쪽 끝에서만 데이터를 삽입하고 삭제할 수 있는 특수한 선형 테이블입니다. 함수 매개변수 값, 지역 변수 등을 저장하는데 사용할 수 있는 저장 구조입니다.

  • 힙은 모든 노드의 값이 해당 자식 노드의 값보다 크거나 같고, 루트 노드의 값이 가장 크거나 작은 것이 특징인 특별한 트리 구조입니다. 힙은 정렬, 검색 등 대용량 데이터를 저장하는 데 사용할 수 있는 동적 저장 구조입니다.

코루틴의 최하위 레이어

코루틴의 핵심은 경량 스레드입니다. 각 코루틴에는 함수와 해당 매개변수, 지역 변수 등을 저장하는 스택이 있습니다. 코루틴을 일시 중지하고, 재개하고, 전환할 수 있습니다.

C# GC(가비지 수집) 원리

  1. 참조 카운트: 객체가 참조되면 참조 카운트는 1씩 증가합니다. 참조가 무효화되면 참조 카운트는 1씩 감소합니다. 개체의 참조 횟수가 0이 되면 해당 개체는 가비지 수집기에 의해 회수됩니다.
  2. 표시 및 지우기: 가비지 수집기가 실행 중일 때 참조 관계에 따라 개체를 순회하고, 액세스 가능한 개체를 "살아있음"으로 표시하고, 액세스할 수 없는 개체를 "죽음"으로 표시한 다음 "죽음"으로 표시된 모든 개체를 지웁니다.
  3. 복사 알고리즘: 가비지 컬렉터는 사용 가능한 메모리를 두 개의 블록으로 나누어 한 번에 하나의 블록만 사용합니다. 공간이 부족하면 살아남은 개체를 다른 공간 블록에 복사한 다음 복사된 개체를 원본에서 지웁니다. 공간.
  4. 표시 보완 알고리즘: 가비지 수집기가 실행 중일 때 먼저 남아 있는 모든 개체를 표시한 다음 남아 있는 모든 개체를 한쪽 끝으로 이동하여 사용되지 않는 공간 조각을 지웁니다.

상태 동기화와 프레임 동기화의 차이점

상태 동기화 다중 기계 시스템에서 각 기계의 상태(예: 위치, 속도, 가속도 등)를 각 제어 주기에서 다른 기계로 전송하여 각 기계가 동기화를 유지하는 것을 의미합니다. 상태 동기화는 다중 기계 공동 제어의 실시간 성능을 달성할 수 있지만 각 제어 주기마다 많은 양의 데이터를 전송해야 하기 때문에 정확도가 상대적으로 낮을 수 있습니다.

프레임 동기화 이는 각 제어 사이클에서 다중 기계 시스템에 있는 각 기계의 제어 명령이 다른 기계로 전송되어 각 기계가 동기화된 상태를 유지한다는 의미입니다. 프레임 동기화는 다중 기계 공동 제어의 정확성을 달성할 수 있지만 각 제어 주기마다 소수의 제어 명령만 전송되므로 실시간 성능이 상대적으로 낮을 수 있습니다.

일반적인 디자인 패턴

싱글톤 패턴
팩토리 패턴
복합 패턴
프록시 패턴

연결 목록, 이진 트리 및 해시 테이블의 특성

1. 연결 목록:
  • 이는 선형 리스트 구조로, 각 노드에는 다음 노드를 가리키는 포인터가 있어 연결 리스트를 형성하는 것이 특징입니다.
  • 노드를 삽입하거나 삭제하더라도 포인터의 위치만 변경하면 되며 시간 복잡도는 O(1)입니다.
  • 노드를 찾는 시간 복잡도는 O(n)이며, 헤드 노드부터 순서대로 탐색해야 합니다.
  • 연결된 목록은 공간 할당 문제를 고려할 필요가 없습니다. 일반적으로 메모리의 동적 할당은 유연한 메모리 관리를 달성하는 데 사용됩니다.
2. 이진 트리:
  • 이진 트리는 각 노드가 최대 2개의 자식을 갖는 트리 구조입니다.
  • 이진 트리의 검색, 삽입 및 삭제 작업의 시간 복잡도는 각각 O(log2n), O(log2n) 및 O(log2n)입니다.
  • 이진 트리의 각 노드는 연속적으로 저장되지 않고 계층적으로 저장되며, 각 노드는 자식을 2개만 가질 수 있으므로 저장 공간을 보다 효율적으로 사용할 수 있다.
3. 해시 테이블:
  • 해시 테이블은 조회 속도를 높이기 위해 레코드에 액세스하기 위해 키를 테이블의 위치에 매핑하는 데이터 구조입니다.
  • 해시 테이블의 검색 시간 복잡도는 O(1)이고, 삽입 및 삭제 시간 복잡도는 O(n)입니다.
  • 해시 테이블을 구현하려면 해시 테이블 자체를 저장할 추가 공간이 필요하며, 해시 충돌 문제를 해결해야 합니다.

HashMap의 기본 원리

HashMap의 하위 계층은 배열 연결 목록(red-black tree)을 사용하여 구현됩니다. 이는 키의 hashCode 값에 따라 데이터를 저장하며 해시를 기반으로 배열 내 데이터 위치(해시 충돌)를 계산할 수 있습니다. 코드를 작성하고 연결된 목록(레드-블랙 트리)을 사용하여 데이터를 저장합니다. HashMap Java 8에서는 연결된 목록의 길이가 임계값(기본값 8)을 초과하면 쿼리 효율성을 높이기 위해 레드-블랙 트리로 변환됩니다.용량이 부족하면 자동으로 확장됩니다. 기본 부하율은 0.75이고 확장 방법은 용량의 2배입니다.

연결리스트에 순환이 있는지 확인하는 방법

  1. 해시 테이블을 사용하여 연결 목록의 각 노드를 순회하고 해당 노드의 주소를 해시 테이블에 저장합니다. 현재 노드가 이미 해시 테이블에 존재하는 경우 연결 목록에 순환이 있음을 의미합니다.
  2. 두 개의 포인터를 정의합니다. 느린 포인터는 한 번에 한 단계씩 이동하고, 빠른 포인터는 한 번에 두 단계씩 이동합니다. 빠른 포인터가 느린 포인터를 만나면 연결된 목록에 주기가 있음을 의미합니다.

스택과 큐의 사용 시나리오는 무엇입니까?

브라우저의 앞으로 및 뒤로 기능: 브라우저가 방문한 웹 페이지는 스택 데이터 구조를 통해 앞으로 및 뒤로 기능을 구현할 수 있습니다.

TCP 끈적이 문제에 대해 아는 것이 있나요?

TCP 끈적이 문제는 TCP 프로토콜이 데이터를 전송할 때 데이터를 조각화하지 않아 수신 측에서 수신하는 데이터의 양이 송신 측에서 보낸 데이터의 양보다 많다는 사실을 의미합니다.

TCP 끈적이 문제를 해결하는 방법은 다음과 같습니다.
  1. 송신 측에 구분 기호 추가: 수신 측에서 구분 기호를 받은 후 구분 기호를 기준으로 데이터를 분할할 수 있습니다.
  2. 송신단에 헤더 추가: 송신단은 데이터를 보내기 전에 헤더를 추가합니다. 헤더에는 현재 데이터의 길이 정보가 포함되어 있습니다. 수신단은 헤더의 길이 정보를 기준으로 데이터를 분할합니다.
  3. 송신 측에 버퍼 추가: 송신 측에서는 데이터를 보내기 전에 먼저 데이터를 버퍼에 넣고 매번 버퍼에 있는 데이터의 일부만 전송합니다. 데이터를 받은 후 수신 측에서는 송신 여부를 결정합니다. 데이터의 전체 길이를 기준으로 합니다.

UDP를 사용하여 간단한 TCP를 구현하는 방법

우선, UDP 데이터그램은 TCP/IP 프로토콜에서 3방향 핸드셰이크 프로세스를 구현하는 데 도움이 될 수 있습니다. 첫 번째 핸드셰이크에서 클라이언트는 핸드셰이크 요청이 포함된 UDP 데이터그램을 보냅니다. 서버가 이 메시지를 받으면 서버가 클라이언트의 핸드셰이크 요청을 받았고 서비스를 제공할 준비가 되었음을 나타내는 확인 메시지로 응답합니다. 두 번째 핸드셰이크에서 클라이언트는 UDP 데이터그램을 다시 보냅니다. 이번에는 서버가 클라이언트를 식별할 수 있도록 클라이언트의 IP 주소, 포트 번호 등과 같은 유용한 정보가 메시지에 포함됩니다. 세 번째 핸드셰이크에서 서버는 연결이 설정되었으며 클라이언트가 데이터 전송을 시작할 수 있음을 나타내는 UDP 데이터그램을 보냅니다.

둘째, UDP 데이터그램은 TCP/IP 프로토콜에서 데이터 전송 프로세스를 실현하는 데 도움이 될 수도 있습니다. 클라이언트가 서버에 데이터를 보내야 하는 경우 데이터는 UDP 데이터그램으로 캡슐화되어 서버로 전송됩니다. 서버는 UDP 데이터그램을 수신한 후 메시지에 포함된 데이터를 구문 분석하고 관련 처리를 수행합니다.

마지막으로 UDP 데이터그램은 TCP/IP 프로토콜에서 종료 프로세스를 구현하는 데도 도움이 될 수 있습니다.클라이언트가 더 이상 서버와 통신할 필요가 없으면 클라이언트가 연결을 종료한다는 것을 나타내기 위해 UDP 데이터그램을 보낼 수 있습니다. 서버는 이 메시지를 받은 후 해당 리소스를 해제하여 전체 TCP/IP 프로토콜을 완료합니다. . 연결 과정

코루틴을 사용해 보셨나요? 코루틴을 사용하는 이유는 무엇입니까?코루틴이 더 빠른 이유

코루틴을 사용하면 프로그램이 서로 다른 작업 간에 전환할 수 있으므로 프로그램 효율성이 향상되고 프로그램 실행 시간이 단축됩니다. 코루틴을 사용하면 프로그램이 한 작업이 완료될 때까지 기다리지 않고 다른 작업을 시작하는 대신 여러 작업 간에 전환할 수 있습니다. 또한 서로 다른 스레드 간에 변수를 공유하여 프로그램 실행 시간을 줄일 수 있습니다. 멀티태스킹 애플리케이션의 경우 코루틴을 사용하면 성능이 크게 향상되어 실행 속도가 빨라질 수 있습니다.

같은 길이의 배열이나 연결 리스트를 순회하는 것이 더 빠릅니까? 왜?

배열의 각 요소의 주소는 연속적이고 고정되어 있고, 다음 요소의 주소를 빠르게 얻을 수 있는 반면, 연결 리스트의 각 요소의 주소는 불연속적이고, 포인터를 순회해야 하기 때문에 배열이 더 빠릅니다. 다음 요소의 주소를 얻으려면 Traversing 배열이 더 빠릅니다.

가상 기능에 대해 이야기해 보겠습니다. 왜 가상 기능이 필요한가요?

가상 함수는 컴파일러에 의해 자동으로 정의되고 컴파일 타임에 호출될 수 있다는 점에서 일반 함수와 다른 특수 함수입니다. 가상 함수의 특징은 구현이 컴파일 타임이 아닌 런타임에 결정된다는 것입니다.
가상 함수의 주요 목적은 다형성을 달성하는 것입니다. 추상 클래스는 여러 가상 함수를 정의할 수 있으며 그 하위 클래스는 이러한 함수를 구현할 수 있습니다.

소멸자는 가상 함수가 될 수 있나요? 가상 함수여야 합니까? 왜? 가상 함수가 아니면 무슨 문제가 있나요?

꼭 가상 함수일 필요는 없으나 일반적으로 가상 함수를 사용하는 것이 좋습니다. 왜냐하면 가상 함수는 파생 클래스에 의해 재정의될 수 있기 때문에 파생 클래스의 소멸자가 가상 ​​함수라면 올바르게 실행될 수 있기 때문입니다. 사용되지 않으면 파생 클래스의 소멸자가 호출되지 않으므로 메모리 누수와 같은 문제가 발생할 수 있습니다.

렌더링 파이프라인 소개

렌더링 파이프라인은 게임 장면 데이터를 입력 정보에서 화면에 표시되는 이미지로 변환하는 데 사용되는 일련의 단계입니다.

렌더링 파이프라인 프로세스는 준비 단계, 지오메트리 단계, 조명 단계의 세 가지 주요 단계로 나뉩니다.

준비 단계에서 게임 엔진은 게임 장면의 모델과 텍스처를 그래픽 처리 장치(GPU)에 로드하고 후속 단계에서 사용할 데이터를 구성합니다.

기하학 단계에서는 행렬 변환을 사용하여 모델을 3차원 공간에 배치하고 모델을 화면의 픽셀이 지원할 수 있는 형태로 변환합니다.

조명 단계에서는 광원과 조명 모델을 사용하여 각 픽셀의 색상 값을 계산하고 결과 이미지가 최종적으로 화면에 표시됩니다.

이진 검색 트리의 삽입, 질의, 삭제 작업에 대해 이야기해 볼까요? 시간 복잡도는 어떻게 되나요?

  1. 끼워 넣다:
  • 시간 복잡도: O(log n)
  • 단계:
  1. 삽입할 노드를 루트 노드부터 시작하여 새 리프 노드로 처리합니다.
  2. 삽입할 노드 값이 현재 노드 값보다 작은 경우 현재 노드의 왼쪽 자식 노드로 이동합니다.
  3. 삽입할 노드 값이 현재 노드 값보다 크면 현재 노드의 오른쪽 자식 노드로 이동합니다.
  4. 현재 노드에 자식 노드가 없으면 삽입할 노드는 현재 노드의 자식 노드가 됩니다.
  5. 그렇지 않으면 자식 노드가 없는 노드를 찾을 때까지 2~4단계를 반복하고 삽입할 노드가 이 노드의 자식 노드로 사용됩니다.

탐욕 알고리즘이 최적의 해를 얻기 위한 조건은 무엇입니까?

최적의 솔루션을 얻기 위한 탐욕 알고리즘의 조건은 "최적 하위 구조"와 "탐욕 선택 속성"입니다.

  1. 최적의 하위 구조: 문제에 대한 최적의 솔루션에는 문제의 하위 문제에 대한 최적의 솔루션이 포함됩니다.
  2. 탐욕적 선택 속성: 각 단계에서 지역적 최적 선택이 이루어지며, 최종 결과는 전역 최적해입니다.