오늘의 코드카타
고고학 최고의 발견
- 종속적인 관계 + 시뮬레이션
- DFS
- LV3 - 14%
-> 문제 풀이
오늘의 공부
팀 프로젝트 진행 상황
1. 문 액터에 멀티플레이 추가
- 인터랙션 컴포넌트에서 상호작용을 시도하면 클라이언트에서만 함수가 실행되게 됨
-> 클라이언트의 입력(플레이어 컨트롤러)을 통해서 해당 함수가 실행되기 때문에 클라에서만 실행
- 상호작용하고 싶은 액터의 인터랙트 함수를 실행시키는 것은 서버에서만 실행
// EGInteractionComponent.cpp
void UEGInteractionComponent::PerformInteraction()
{
...
if (GetWorld()->LineTraceSingleByChannel(Hit, StartLoc, EndLoc, ECC_Visibility, Params))
{
if (AActor* HitActor = Hit.GetActor())
{
if (HitActor->GetClass()->ImplementsInterface(UEGInteractInterface::StaticClass()))
{
if (!GetOwner()->HasAuthority())
{
ServerRPC_Interact(HitActor);
}
}
}
}
}
void UEGInteractionComponent::ServerRPC_Interact_Implementation(AActor* Target)
{
if (Target && Target->GetClass()->ImplementsInterface(UEGInteractInterface::StaticClass()))
{
IEGInteractInterface::Execute_Interact(Target);
}
}
- 문의 열고 닫힘 상태를 관리하는 변수를 추가
- 서버에서만 해당 변수를 수정해서,
ReplicatedUsing 속성을 활용해서 서버, 클라에서도 같이 TimelineComponent를 활용해서 문을 열고 닫음
// EGDoor.h
UFUNCTION()
void OnRep_DoorState();
UPROPERTY(ReplicatedUsing = OnRep_DoorState)
bool bIsOpen;
// EGDoor.cpp
void AEGDoor::Interact_Implementation()
{
if (HasAuthority())
{
bIsOpen = !bIsOpen;
}
}
void AEGDoor::OnRep_DoorState()
{
if (bIsOpen)
{
DoorTimeline->PlayFromStart();
}
else
{
DoorTimeline->ReverseFromEnd();
}
}
2. 타임라인 컴포넌트 오류 수정
- 문 인터랙트를 광클할 시에, 타임라인 오류인지 처음이나 끝 부분으로 텔포하는 에러 발생
-> 타임라인 재생 중에는 문 인터랙트 막기
void AEGDoor::Interact_Implementation()
{
if (HasAuthority())
{
if (!DoorTimeline->IsPlaying())
{
bIsOpen = !bIsOpen;
OnRep_DoorState();
}
}
}
- 문 열고 닫힘은 동기화가 잘 됨
- 다만, 문 열고 닫을 때, 물리 계산이 이상하게 다르게 되는 경우가 있음
3. NavMesh 동적 생성 R&D
오늘의 CS
가상 메모리
- 개념
- 프로세스의 일부만 메모리에 로드하고, 나머지는 디스크에 둔 상태로 프로세스를 실행하는 방식
- 실제 물리 메모리(RAM)보다 더 큰 메모리 공간이 있는 것처럼 제공하는 기술
- SSD/HDD 일부를 RAM처럼 사용
- 장점
- 물리 메모리 부족 문제 완화
- 동시에 많은 프로그램을 실행하므로 CPU 이용률과 처리율을 높일 수 있음
- 필요한 영역만 메모리에 로드해 스와핑 횟수를 줄여서 프로그램 실행 속도를 높일 수 있음
- MMU(Memory Management Unit)가 두 주소 사이의 변환을 담당해서, CPU가 가상 주소를 요청하면, 이를 물리 주소로 변환하여 실제 메모리에 접근함
- 프로세스는 처음에 메모리 영역을 할당받을 때, 할당받은 모든 영역을 PTE(Page Table Entry)에 등록이 되고, 이를 기반으로 가상 메모리 주소를 만들어서 관리함
페이징
- 가상 메모리 시스템은 메모리를 일정한 크기로 나눈 블록 단위로 관리함
- 페이지
- 프레임
- 페이징
- 가상 주소 공간의 페이지를 물리 메모리의 프레임에 매핑하는 기법
- 동작 과정
- 각 프로세스는 자신의 페이지 테이블을 가짐
- 페이지 테이블은 가상 메모리의 페이지 번호와 물리 메모리의 프레임 번호를 연결해줌
- CPU가 가상 주소를 생성하면, MMU는 페이지 테이블을 참조하여 해당하는 물리 주소를 찾음
CPU가 메모리 접근할 때의 동작 과정
1. CPU -> 캐시 확인
- CPU는 항상 가상 주소로 메모리에 접근
- 가상 주소를 변환해서 실제 물리 주소를 알아낸 뒤, 해당 주소가 L1 -> L2 -> L3 캐시에 있는지 확인
2. 주소 변환
- CPU는 물리 주소를 모름 -> MMU가 변환
- TLB 확인 (페이지 테이블의 캐시)
- TLB에 가상 주소 -> 물리 주소 매핑이 있으면 변환
- 없으면 TLB 미스 -> 페이지 테이블 조회
- 페이지 테이블에서 해당 가상 주소가 어느 물리 프레임에 매핑되어 있는지 확인
- 있으면 변환 성공, 그 결과를 TLB에 캐싱해둠
- 없으면 페이지 폴트 발생
3. 페이지 폴트 처리
- 페이지 폴트 발생 : 해당 가상 페이지가 현재 RAM에 없음
-> 즉 페이지 테이블에 프레임과 매핑이 되어있지 않음
- OS가 디스크에서 해당 페이지를 읽어서 RAM에 올림
- RAM에 새로 올라간 페이지의 매핑 정보를 페이지 테이블에 기록, TLB에도 캐싱
4. 데이터 로드
- RAM -> 캐시에 데이터를 올리고, CPU가 해당 데이터를 읽음
32비트 운영체제 vs 64비트 운영체제
1. 주소 공간
- 32비트 OS
- CPU 레지스터가 32비트 -> 주소 공간은
2^32 = 4GB
- 하나의 프로세스가 최대 4GB 가상 메모리만 접근 가능
- 64비트 OS
- 주소 공간은
2^64 -> 이론상 16EB(엑사바이트)
- 훨씬 많은 메모리를 직접 주소 지정 가능
2. 레지스터 크기 & 연산 단위
- 32비트 OS
- 범용 레지스터 크기 : 32비트
- 한 번에 처리 가능한 정수 크기 : 4바이트
- 포인터 크기 : 4바이트
- 64비트 OS
- 범용 레지스터 크기 : 64비트
- 한 번에 처리 가능한 정수 크기 : 8바이트
- 포인터 크기 : 8바이트
3. 메모리 활용 & 소프트웨어 호환성
- 32비트 OS
- 4GB 이상 RAM을 인식 불가
- 32비트 프로그램만 실행 가능
- 64비트 OS
- 수십 GB 이상 RAM 자유롭게 사용 가능
- 단, 포인터가 커서 -> 같은 프로그램도 메모리를 조금 더 많이 사용
- 64비트 프로그램 실행 가능, 대부분의 32비트 프로그램도 호환해서 실행 가능