시작시 많은 양의 메모리를 할당하고 해제하는 것이 "메모리 정리"입니까?


18

Book Game Coding Complete, Fourth Edition , chapter 5 ( Game Initialization and Shutdown ), Checking Memory 섹션 에는이 흥미로운 코드 샘플이 포함되어 있습니다.

bool CheckMemory(const DWORDLONG physicalRAMNeeded, const DWORDLONG virtualRAMNeeded)
{
    MEMORYSTATUSEX status; 
    GlobalMemoryStatusEx(&status);
    if (status.ullTotalPhys < physicalRAMNeeded) 
    {
        // you don’t have enough physical memory. Tell the player to go get a 
        // real computer and give this one to his mother. 
        GCC_ERROR("CheckMemory Failure: Not enough physical memory."); 
        return false;
    }
    // Check for enough free memory.
    if (status.ullAvailVirtual < virtualRAMNeeded) 
    {
        // you don’t have enough virtual memory available.
        // Tell the player to shut down the copy of Visual Studio running in the 
        // background, or whatever seems to be sucking the memory dry. 
        GCC_ERROR("CheckMemory Failure: Not enough virtual memory.");
        return false;
    }

    char *buff = GCC_NEW char[virtualRAMNeeded]; 
    if (buff)
    {
        delete[] buff;
    }
    else
    {
        // even though there is enough memory, it isn't available in one
        // block, which can be critical for games that manage their own memory 
        GCC_ERROR("CheckMemory Failure: Not enough contiguous memory."); 
        return false;
    }
}

이것은 몇 가지 질문을 제기합니다.

첫 번째 부분은 OS (Windows)에 사용 가능한 물리적 RAM의 양을 묻습니다. 흥미로운 부분은 두 번째 부분으로, 엄청난 양의 메모리를 할당하고 즉시 해제합니다.

char *buff = GCC_NEW char[virtualRAMNeeded]; 
if (buff)
{
    delete[] buff;
}

저자는 다음과 같이 설명합니다.

...이 함수는 거대한 메모리 블록을 할당하고 즉시 해제합니다. 이렇게하면 메모리 관리자에 누적 된 가비지를 Windows에서 정리하고 필요한만큼 연속 블록을 할당 할 수 있는지 다시 확인하는 효과가 있습니다. 전화가 성공하면 기본적으로 시스템 메모리를 통해 잠보니 머신과 동등한 기능을 실행하여 게임이 얼음에 부딪 칠 수 있도록 준비합니다.

그러나 나는 그것에 대한 나의 예약이있다.

"메모리 관리자에 쌓인 가비지 청소?" 정말? 게임이 방금 시작된 경우 쓰레기가 없어야합니까?

"연속 블록을 할당 할 수 있는지 확인 하시겠습니까?" 메모리를 직접 관리하려는 매우 구체적인 경우에는 이것이 의미가 있지만 여전히 많은 양의 메모리를 할당하면 다른 응용 프로그램을 실행할 수 없게됩니다. 당신이 켜져있는 동안 시스템.

또한 이것이 OS가 모든 메모리를 커밋하여 스왑 디스크 공간에 많은 메모리를 제거하여 앱 시작 속도를 크게 떨어 뜨리지 않을 가능성이 있습니까?

이것이 실제로 좋은 습관입니까?


3
대부분의 최신 운영체제가 응용 프로그램 할당 메모리의 넓은 지역에, 그들은 메모리를 채울 낙관적 할당을 사용하고 실제로 때까지 아무것도하지 않는 전혀 아무것도하지 않는 것, 좀 더 시간이 걸리는에는 조합되는없는 것보다 아무것도이 상상할 수 없다
Vality에서을

정글에서 긴 땅을 치우고, 나무에서 라디오, 헤드폰 등을 조각하면 비행기가 착륙하여 물품을 배달합니까?
Dan Neely

10
전체 코딩 게임 포함 을 많이 하지-이해-C ++와 C-그-외모-A-비트-C와 같은 ++ (도의 결과 확인이 샘플에서 설명의 많은 쌍 말도 안되는을 operator new위한을 nullptr), 당신은 저를 허용하는 경우 말을 그 책으로 할 수있는 가장 좋은 일은 굴뚝을 가볍게하는 것입니다. 물론 큰 메모리 블록을 할당하고 해제 해도 메모리가 "정리" 되지 않습니다 .
데이먼

@Damon, 확인하지는 않았지만 전역 new연산자가 오버로드되어 null 대신 null을 반환하도록 의심했습니다 bad_alloc. 그렇지 않다면,이 코드는 훨씬 더 무의미합니다. : P
glampert

1
@ glampert :이 경우를 가정하더라도 이를 no-op로 operator delete받아들이고 nullptr취급해야합니다. 이를 수행하지 않는 전역 과부하가 발생했습니다. 어느 쪽이든 말도 안되는 의미입니다. 거대한 메모리 블록을 할당하고 해제한다고 가정하면 "마 법적으로"좋은 일을 할 것입니다. 기껏해야 아무런 해를 끼치 지 않습니다 (페이지를 건드리지 않았기 때문에 가능성이 높습니다 ... 그렇지 않으면 나중에 다시로드 해야하는 작업 세트에서 일부 페이지가 바뀔 수 있습니다).
데이먼

답변:


12

메모리의 큰 덩어리 미리 할당한다는 것은 컴퓨터가 낮은가 RAM에 있던 경우 수행은 디스크에 다른 프로그램 메모리 공간의 일부를 교환하여 일부 여분의 공간을 확보하기 위해 OS를 강제로 수 있습니다.

이러한 스와핑은 일반적으로 매우 느린 작업이므로 프로그램이 진행되는 동안 프로그램이 거의 정지되므로 어쨌든 게임이 진행되는 동안 게임이 시작 되기 전에 게임이 시작 되기 전에 발생할 수 있다는 이점이 있습니다 .

즉, 이와 같은 디스크 스왑을 강제하는 것은 정확히 100 % 신뢰할 수는 없습니다.

  • 많은 가상 메모리 구현에서 단순히 메모리 할당 만 실제로 스와핑을 트리거하지는 않습니다. 오히려 할당 한 메모리의 각 페이지에 처음 액세스 할 때만 발생합니다. (이것은 기본적으로 메모리 오버 커밋이 활성화 된 최신 버전의 Linux에서는 확실합니다 .Windows의 다른 버전이 어떻게 처리하는지 확실하지 않습니다.)

    따라서이 코드가 메모리를 "정리" 하기를 원한다면 릴리스하기 전에 memset()배열의 모든 부분 (또는 적어도 첫 번째 physicalRAMNeeded바이트에) 에 실제로 데이터를 쓰려면 호출 또는 이에 상응하는 항목을 추가해야 합니다.

  • 또한,이 같은 RAM에서 스왑 다른 프로그램에 OS를 강제로가 있습니다 것을 의미하지 않는다 남아 그것을 밖으로. Windows는 멀티 태스킹 OS이며, 스왑 아웃 된 프로그램 중 하나가 다시 실행되고 스왑 아웃 된 데이터를 사용하려는 즉시 다시 스왑되어 게임이 다시 정지 될 수 있습니다.

    따라서이 트릭은 일반적으로 RAM에 적극적으로 액세스하지 않는 많은 양의 데이터 (예 : 일부 편집 소프트웨어에서 백그라운드로 열린 큰 문서)에 의해 RAM을 사용하는 경우에만 유용합니다. 웹 브라우저는 이와 관련하여 특히 문제가되는 경향이 있습니다. 실제로 일부 백그라운드 탭에서 열린 웹 페이지를 사용하지 않더라도 페이지에 여전히 스크립트가 실행되어 RAM에 유지되도록 할 수 있습니다.

    (이 있습니다 실제로 RAM에 메모리 공간의 일부를 고정하기 위해 OS를 이야기하고 스왑 아웃되는 것을 방지하지만, 이러한 일반적으로 상승 된 권한을 필요로하는 프로그램을위한 방법. 어떤 경우에는, 당신이 게시 코드로 표시되지 않습니다 그러한 방법을 사용하십시오.)

기본적 으로이 트릭은 사용자 스왑없이 게임을 실행하기에 충분한 RAM (및 백그라운드에서 실제로 실행중인 다른 소프트웨어)이 있지만 RAM이 현재 비활성 및 사용되지 않는 열린 파일로 채워져있는 비교적 좁은 경계선 상황에서만 유용 합니다. 게임이 실행되는 동안 디스크로 스왑 가능해야하는 다른 데이터. 이러한 상황에서는 게임 플레이 중 작은 스왑 작업을 시작하는 동안 단일 스왑 작업으로 교체하여 게임을보다 부드럽고 반응 적으로 보이게하는 것이 효과적 일 있습니다.


1
저수준 메모리 관리에 대한 제한된 지식을 바탕으로 특정 페이지를 스왑할지 여부를 결정하는 것이 훨씬 복잡하며 단순히 요청 된 메모리 양과 사용 가능한 메모리 양보다 많은 요소를 고려한다고 말할 수 있습니다. . 이것을 지나치게 단순화하고 일반적으로 가정에 의존하는 것은 그리 현명하지 않습니다.
판다 파자마

3
나는이 모든 것이 효과가 있거나 효과가 없거나 효과가없는 것처럼 보일 수 있지만 완전히 관련이없는 이유라는 것을 기억하는 것이 중요하다고 생각합니다. 내가 아는 한,이 답변에서 지적한 행동은 문서화되지 않았으며, 그것에 의존하는 것은 현명하지 않습니다. OS 업데이트, 설정 변경, 컴파일러 변경 또는 거의 모든 것이 이로 인해 작동이 중지되거나 성능에 부정적인 영향을 줄 수 있습니다.
Panda Pajama

26

나는 그 글이 몇 살인지 모르겠지만 꽤 오래되었다고 말할 것입니다. 현대 Windows (XP 이상, 특히 64 비트 버전)에서는 이와 같은 작업을 수행하면 게임 시작에 거의 또는 부정적인 영향을 미칩니다.

우선, 주소 공간은 각 프로세스마다 가상화된다는 것을 기억하십시오. 프로세스와 관련하여 전체 주소 공간이 있으며 메모리가 물리적으로 연속적인지 여부에 관계없이 항상 인접한 (가상) 메모리를 얻게됩니다.

실제로 메모리가 물리적 메모리에서 연속적인지 여부는 사용자가 제어 할 수있는 것이 아닙니다. OS는 물리적 블록을 적절하게 할당하는 방법을 선택하며 응용 프로그램 수준에서 수행하는 작업은 연속 물리적 메모리를 갖는 이점에 영향을 줄 수 없습니다.

매우 긴 시간 동안 서로 다른 크기의 메모리를 할당하고 해제하는 경우 가상 메모리 조각화에주의해야합니다. 이것은 물론 64 비트 주소 공간과 관련성이 훨씬 낮습니다. 게임은 일반적으로 몇 달 동안 실행되지 않으므로 오랫동안 실행되는 게임 서버에 대해 이야기하지 않는 한 이에 대해 신경 쓸 필요가 없습니다.

32 비트 시스템에서 엄청나게 다른 크기의 메모리를 많이 할당하더라도 최신 메모리 할당은 꽤 좋으므로 적극적으로 찾지 않으면 가상 메모리 조각화 문제가 발생하지 않습니다.

솔직히 말해서 그 작가가 무슨 일을하는지 모르겠습니다. 주소 공간이 공유 되어도 실제 메모리에 거대한 연속 블록이 생겨나면 더 이상 신경 쓰지 않는다고 말하는 것입니다. 백그라운드에서 자체 할당을 수행하는 다른 프로그램이 있으므로 거대한 malloc이 성공하더라도 다음 프로그램도 성공할 것이라고 아무도 보장하지 않습니다.

나는 그것이 실제로 이해하지 못하는 어떤 이유로 일했기 때문에 그것을 설명하기 위해 무언가를 만들었다 고 생각합니다.


10
RAM은 연속적인 블록을 갖는 것이 어떤 방식 으로든 "더 나은"회전 하드 디스크와는 다릅니다. 사실이 아닙니다. 연속 RAM 액세스는 임의 액세스보다 훨씬 빠릅니다. RAM 칩은 일정 지연 시간으로 전환되는 섹션으로 나뉘며, 더 중요한 것은 L1 및 L2 캐시 미스가 메모리가 분산 될 때 성능에 큰 영향을 미칩니다.
CaptainCodeman

@CaptainCodeman : 내 지식의 범위를 벗어난 것을 받아 들여야하지만 Windows 응용 프로그램 프로그래머는 메모리가 물리적으로 연속적인지 여부를 제어 할 수 없습니다. 거대한 메모리 블록을 요구해도 큰 변화는 없습니다.
Panda Pajama

@CaptainCodeman은 실제로 인접한 가상 블록을 가지고 있습니다. mod 2 ^ N RAM의 블록은 캐시 라인 할당으로 인해 속도가 빨라집니다.
ratchet freak

8
@CaptainCodeman 그래, 순차 DRAM 액세스는 빠르지 만 4KB 이상의 페이지에서 발생하는 가상-> 물리적 매핑에 대해 이야기하고 있으므로 매핑이 순차적인지 메모리에 큰 영향을 미치지 않아야하는지 여부 읽기 속도. 또한 캐시 프리 페치 및 이와 유사한 기능은 물리적 주소가 아닌 가상 주소 공간에서 작동합니다.
Nathan Reed

1
@NathanReed Fair로 충분하고 명확하게 해 주셔서 감사합니다. 방금 제안한 것처럼 RAM 액세스 속도가 메모리 공간에서 완전히 균일하지 않다는 것을 표현했습니다.
CaptainCodeman
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.