yuchi's Development Home
글 수 201
라이트맵을 빌드할때는 어쨌거나 각 텍셀에 대한 3차원 좌표와 노멀값을 저장해놓고 있어야한다.
해보신 분은 아시겠지만 이게 용량이 만만치가 않다. 맵이 한 2km*2km쯤 되어도 진짜 살인적이다.
하여간 이놈이 메모리를 많이 쳐먹기 때문에 임시파일로 저장해놓고 라이트맵 빌드할때마다 디스크에서 읽어와서 계산하게 할 생각이었다.
근데 해보니 대부분의 상황에선 또 그렇게까지 치명적으로(어디까지나 상대적으로) 메모리를 많이 먹는건 아니었다.
뭣보다도...위대한 NT커널이 페이징을 훌륭하게 해주기 때문에 내가 굳이 하드디스크에 스왑시켜주지 않아도 그냥 메모리에 올려놓으면 알아서 페이징이 될터.
해서 빌드 한번 하면 엔진 내려갈때까지(툴이 종료될때 엔진도 종료시키니까) 라이트맵 패치 데이타를 메모리에 유지시키도록 했다.
그런데 얼마전에 노트북에서 테스트 하던 중 의외의 복병을 만났다.
그 라이트맵 패치 빌드하는 과정에서 메모리 할당에 실패한 것이다.
1기가 가까운 용량을 요구하긴 했지만..뭐 노트북도 메모리 2기가 꽂혀있는데? 할당에 실패할리가?
아차차. 생각해보니, 집이나 회사에서 쓰는 데스크탑은 64비트 머신에 , 64비트 os다.
64비트 프로세스와 32비트 프로세스의 어드레스 영역의 차이는 대우주와 개구리 살고 있는 연못의 차이랄까.
역시 메모리를 적게 쓰는 소프트가 잘 돌아갈 가능성이 높은 소프트웨어다.
해서 패치 생성,유지는 디스크에 스왑할 수 있도록 고치기로 하고 오늘(아니 어제군.새벽이니) 코드를 뜯어봤다.
라이트맵 코드에 페이징 코드를 막바로 넣는 것은 좀 그렇고...지저분해.
흠..뭔가 좀 우아하게 할 순 없을까. 이번에 짠 코드를 두고두고 재활용 할 수는 없을까.
그래. 범용적으로 쓸 수 있는 메모리 풀을 만들자. 페이징 기능이 있는 메모리 풀을 만드는거다.
간단하게 요구 스펙을 적어보면 다음과 같다.
1. 사용할 물리 메모리에 제한을 걸 수 있다.
2. 사용한 물리 메모리가 제한치를 초과하는 경우 물리메모리에 들어있는 내용을 자동으로 디스크로 저장하고, 물리 메모리를 반환시킨다.
3. 사용 빈도가 낮은 메모리부터 페이지아웃 시킨다.
5시간 정도 코딩해서 방금 콘솔 모드 테스트를 마쳤다.
인터페이스는 다음과 같다.
// 초기화 함수
BOOL CPagedMemory::Initialize(DWORD dwMaxPhysicalMemory,DWORD dwMaxMemBlockNum,WCHAR* wchPagingFileName,DWORD dwPagingFileSize,DWORD dwPageOutUnitSize);
dwMaxPhysicalMemory - 물리 메모리 최대 사용량. 이 수치를 초과하면 페이지 아웃시킨다.
dwMaxMemBlockNum - 할당할 수 있는 메모리 블럭 최대 개수
wchPagingFileName - 페이징 파일을 생성할때 부여할 파일명
dwPagingFileSize - 페이징 파일 사이즈. 가변 크기로 하려고 했으나 윈도우에서도 고정 사이즈를 사용한다는 것을 상기하고 그냥 고정으로 짰다.
dwPageOutUnitSize - 한번에 페이지 아웃 시킬 메모리 크기
// 메모리 할당 함수
// 리턴값은 메모리 핸들
PAGED_MEMORY_HANDLE CPagedMemory::Alloc(DWORD dwSize,OnPageOutFunc pFunc);
dwSize - 할당할 메모리 크기
pFunc - 페이지 아웃 될때 자동 호출될 콜백함수 포인터
// 할당한 메모리를 해제하는 함수
void CPagedMemory::Free(PAGED_MEMORY_HANDLE hMem);
hMem - Alloc()함수로 할당받은 메모리 핸들
// 메모리 핸들을 실제 물리 메모리로 맵핑하는 함수
// 커널이 아닌 유져모드에서 구현한 페이징이다보니 이런 거추장 스러운 방법밖에 쓸 수 없다.
// 이 함수의 사용빈도에 따라 각 메모리 블럭의 페이지 아웃 가능성이 정해진다.
BOOL CPagedMemory::UpdatePhyMemPtr(void** ppOutPhyMemPtr,PAGED_MEMORY_HANDLE hMem);
ppOutPhyMemPtr - 물리 메모리가 저장될 어드레스
hMem - 물리 메모리를 얻어올 메모리 핸들
일단 콘솔모드 테스트 프로그램으로는 문제가 없다.
라이트맵 생성 코드에 직접 넣어보면 확실히 알 수 있겠지.
디스크 IO가 많이 생겨서 다소 퍼포먼스가 떨어질 것 같은데 그 역시 테스트를 해봐야 알 수 있겠다.
하튼 간만의 새벽코딩.
해보신 분은 아시겠지만 이게 용량이 만만치가 않다. 맵이 한 2km*2km쯤 되어도 진짜 살인적이다.
하여간 이놈이 메모리를 많이 쳐먹기 때문에 임시파일로 저장해놓고 라이트맵 빌드할때마다 디스크에서 읽어와서 계산하게 할 생각이었다.
근데 해보니 대부분의 상황에선 또 그렇게까지 치명적으로(어디까지나 상대적으로) 메모리를 많이 먹는건 아니었다.
뭣보다도...위대한 NT커널이 페이징을 훌륭하게 해주기 때문에 내가 굳이 하드디스크에 스왑시켜주지 않아도 그냥 메모리에 올려놓으면 알아서 페이징이 될터.
해서 빌드 한번 하면 엔진 내려갈때까지(툴이 종료될때 엔진도 종료시키니까) 라이트맵 패치 데이타를 메모리에 유지시키도록 했다.
그런데 얼마전에 노트북에서 테스트 하던 중 의외의 복병을 만났다.
그 라이트맵 패치 빌드하는 과정에서 메모리 할당에 실패한 것이다.
1기가 가까운 용량을 요구하긴 했지만..뭐 노트북도 메모리 2기가 꽂혀있는데? 할당에 실패할리가?
아차차. 생각해보니, 집이나 회사에서 쓰는 데스크탑은 64비트 머신에 , 64비트 os다.
64비트 프로세스와 32비트 프로세스의 어드레스 영역의 차이는 대우주와 개구리 살고 있는 연못의 차이랄까.
역시 메모리를 적게 쓰는 소프트가 잘 돌아갈 가능성이 높은 소프트웨어다.
해서 패치 생성,유지는 디스크에 스왑할 수 있도록 고치기로 하고 오늘(아니 어제군.새벽이니) 코드를 뜯어봤다.
라이트맵 코드에 페이징 코드를 막바로 넣는 것은 좀 그렇고...지저분해.
흠..뭔가 좀 우아하게 할 순 없을까. 이번에 짠 코드를 두고두고 재활용 할 수는 없을까.
그래. 범용적으로 쓸 수 있는 메모리 풀을 만들자. 페이징 기능이 있는 메모리 풀을 만드는거다.
간단하게 요구 스펙을 적어보면 다음과 같다.
1. 사용할 물리 메모리에 제한을 걸 수 있다.
2. 사용한 물리 메모리가 제한치를 초과하는 경우 물리메모리에 들어있는 내용을 자동으로 디스크로 저장하고, 물리 메모리를 반환시킨다.
3. 사용 빈도가 낮은 메모리부터 페이지아웃 시킨다.
5시간 정도 코딩해서 방금 콘솔 모드 테스트를 마쳤다.
인터페이스는 다음과 같다.
// 초기화 함수
BOOL CPagedMemory::Initialize(DWORD dwMaxPhysicalMemory,DWORD dwMaxMemBlockNum,WCHAR* wchPagingFileName,DWORD dwPagingFileSize,DWORD dwPageOutUnitSize);
dwMaxPhysicalMemory - 물리 메모리 최대 사용량. 이 수치를 초과하면 페이지 아웃시킨다.
dwMaxMemBlockNum - 할당할 수 있는 메모리 블럭 최대 개수
wchPagingFileName - 페이징 파일을 생성할때 부여할 파일명
dwPagingFileSize - 페이징 파일 사이즈. 가변 크기로 하려고 했으나 윈도우에서도 고정 사이즈를 사용한다는 것을 상기하고 그냥 고정으로 짰다.
dwPageOutUnitSize - 한번에 페이지 아웃 시킬 메모리 크기
// 메모리 할당 함수
// 리턴값은 메모리 핸들
PAGED_MEMORY_HANDLE CPagedMemory::Alloc(DWORD dwSize,OnPageOutFunc pFunc);
dwSize - 할당할 메모리 크기
pFunc - 페이지 아웃 될때 자동 호출될 콜백함수 포인터
// 할당한 메모리를 해제하는 함수
void CPagedMemory::Free(PAGED_MEMORY_HANDLE hMem);
hMem - Alloc()함수로 할당받은 메모리 핸들
// 메모리 핸들을 실제 물리 메모리로 맵핑하는 함수
// 커널이 아닌 유져모드에서 구현한 페이징이다보니 이런 거추장 스러운 방법밖에 쓸 수 없다.
// 이 함수의 사용빈도에 따라 각 메모리 블럭의 페이지 아웃 가능성이 정해진다.
BOOL CPagedMemory::UpdatePhyMemPtr(void** ppOutPhyMemPtr,PAGED_MEMORY_HANDLE hMem);
ppOutPhyMemPtr - 물리 메모리가 저장될 어드레스
hMem - 물리 메모리를 얻어올 메모리 핸들
일단 콘솔모드 테스트 프로그램으로는 문제가 없다.
라이트맵 생성 코드에 직접 넣어보면 확실히 알 수 있겠지.
디스크 IO가 많이 생겨서 다소 퍼포먼스가 떨어질 것 같은데 그 역시 테스트를 해봐야 알 수 있겠다.
하튼 간만의 새벽코딩.