2012-04-28 2 views
0

블룸 필터 (비트 테이블) 3 차원 char 배열을 사용하여 더 이상 메모리를 할당 할 수있는 지점에 도달 할 때까지 작동하고 bad_alloc 메시지를 제공합니다. 600MB를 할당 한 후 다음 확장 요청시이 오류가 발생합니다.왜 동적 메모리 할당이 600MB 후에 실패합니까?

블룸 필터 (배열)는 8-10GB로 커질 것으로 예상됩니다.

다음은 비트 테이블을 할당 (확장)하는 데 사용되는 코드입니다.

unsigned char ***bit_table_=0; 
unsigned int ROWS_old=5; 
unsigned int EXPND_SIZE=5; 


void expand_bit_table() 
    { 
     FILE *temp; 
     temp=fopen("chunk_temp","w+b"); 
     //copy old content 
     for(int i=0;i<ROWS_old;++i) 
      for(int j=0;j<ROWS;++j) 
       fwrite(bit_table_[i][j],COLUMNS,1,temp); 
     fclose(temp); 
     //delete old table 
     chunk_delete_bit_table(); 
     //create expanded bit table ==> add EXP_SIZE more rows 
     bit_table_=new unsigned char**[ROWS_old+EXPND_SIZE]; 
     for(int i=0;i<ROWS_old+EXPND_SIZE;++i) 
      { 
       bit_table_[i]=new unsigned char*[ROWS]; 
       for(int k=0;k<ROWS;++k) 
        bit_table_[i][k]=new unsigned char[COLUMNS]; 
      } 
     //copy back old content 

      temp=fopen("chunk_temp","r+b"); 
     for(int i=0;i<ROWS_old;++i) 
     { 
      fread(bit_table_[i],COLUMNS*ROWS,1,temp); 
     } 
      fclose(temp); 
     //set remaining content of bit_table_to 0 
     for(int i=ROWS_old;i<ROWS_old+EXPND_SIZE;++i) 
      for(int j=0;j<ROWS;++j) 
       for(int k=0;k<COLUMNS;++k) 
        bit_table_[i][j][k]=0; 

     ROWS_old+=EXPND_SIZE; 
    } 

어레이의 최대 허용 크기는 무엇이며, 이것이 문제가 아닌 경우 무엇을 할 수 있습니까?

편집 : 32 비트 플랫폼을 사용하여 개발되었습니다.

8 비트 RAM이 장착 된 64 비트 플랫폼 (서버)에서 실행됩니다.

+1

이 코드는 눈을 아프게합니다. 틀림없이 작동하지 않습니다. –

+1

640MB는 모두에게 충분해야합니다. 죄송합니다, 나는 그것을 크게 외쳤습니까? 나는 얼마나 많은 기억을 가지고 있으며 이것은 64 비트 환경인가? –

+3

어떤 시스템을 사용하고 있습니까? 32 비트 시스템에 6GB 크기의 배열이있을 것으로 기대할 수 없습니다. [4GB 가상 주소가 있기 때문에 올바르게 기억한다면 약 1GB가 커널 용으로 예약되어 있습니다] 적어도 – amit

답변

5

32 비트 프로그램은 가상 메모리 주소 공간에서 메모리를 할당해야합니다. 코드와 데이터의 덩어리를 저장하며, 메모리는 그 사이의 구멍에서 할당됩니다. 예, 최대 가능한 구멍 인 650 메가 바이트입니다. 그것은 저기에서 급속하게 내려갑니다. 하나의 거대한 배열 대신에 트리 나 목록처럼 데이터 구조를 더 똑똑하게 만들어서 해결할 수 있습니다.

SysInternals의 VMMap 유틸리티를 사용하면 프로세스의 가상 메모리 맵에 대해 더 많은 통찰력을 얻을 수 있습니다. DLL의 기본 주소를 변경하여 주소 공간의 빈 영역의 중간에 위치하지 않도록 할 수 있습니다. 그러나 650MB를 훨씬 넘는 확률은 매우 낮습니다.

운영 체제 구성 요소가 64 비트 모드로 실행되기 때문에 64 비트 운영 체제에는 더 많은 호흡 공간이 있습니다. 32 비트 프로세스에는 4 기가 바이트 주소 공간이 있습니다. 프로세스에서 모두 사용하려면/LARGEADDRESSAWARE 링커 옵션을 사용해야합니다. 여전히 64 비트 OS에서만 작동하지만 프로그램은 여전히 ​​32 비트 OS에서 폭탄을 일으킬 가능성이 있습니다. 그만큼 많은 VM이 필요한 경우 가장 간단한 방법은 64 비트 OS를 필수 조건으로 만들고 x64를 대상으로하는 프로그램을 빌드하는 것입니다.

+0

감사. 플랫폼을 변경하면이 문제가 전혀 발생하지 않는다고 말하는 것입니까? – John

+0

아니요, 64 비트 주소 공간은 페이징 파일의 크기에 의해서만 제한됩니다. –

+0

@HansPassant : 사실이 아닙니다. 유닉스 박스에서, 시스템 관리자는 개별 프로세스가 소비하는 가상 메모리에 하드 및 소프트 제한을 설정할 수 있습니다. 사용자는 소프트 제한을 올릴 수 있지만 하드 제한보다 높게 설정할 수는 없습니다.하지만 John이 64 비트 컴퓨터에서 컴파일하고 실행해야하는 요지의 요지는 정확합니다. +1. –

1

32 비트 프로세스가 액세스 할 수있는 최대 메모리 내 데이터는 이론상 4GB입니다 (실제로는 다소 적음). 따라서 한 번에 10GB의 데이터를 메모리에 저장할 수는 없습니다 (더 많은 OS를 지원하더라도). 또한 메모리를 동적으로 할당하더라도 사용 가능한 무료 저장소는 스택 크기에 의해 더 제한됩니다.

프로세스에 사용할 수있는 실제 메모리는 실행 파일을 생성하는 컴파일러 설정에 따라 다릅니다.

정말 많이 필요하다면 파일 시스템에서 데이터의 일부분을 유지하는 것이 좋습니다.

1

32 비트 컴퓨터는 4GB의 주소 공간을 제공합니다.

OS가이 중 일부가집니다 (자신에게 당신에게 2 기가 바이트 제공, 윈도우에서 기본적으로 그것의 절반을. 나는 리눅스에 대해 잘 모르겠지만, 나는 그것이 1GB의 보유 생각) 이것은 당신이 2를 의미

자신의 프로세스에 3GB.

  • 실행 파일 (뿐만 아니라 모든 동적 링크 라이브러리) 메모리 매핑 그것으로는
  • 각 스레드 스택
  • 힙을 필요가있다 :이 공간에

    는 몇 가지에 맞게 필요

및 기타 몇 가지 중요한 비트가 있습니다.

요점은 실제로 얼마나 많은 메모리가 실제로 실제로 끝나는 것이냐는 것입니다. 을 사용하면을 사용합니다. 그러나 많은 다른 조각들이이 기억 공간에 들어 맞아야합니다. 그리고 그것들은 그것의 한쪽 끝에 단단히 묶여 있지 않기 때문에, 조각 메모리 공간입니다. 단순화를 위해 실행 파일이이 메모리 공간의 중간에 매핑되는 것을 상상해보십시오. 그러면 3GB가 두 개의 1.5GB 청크로 나뉩니다. 이제 두 개의 동적 라이브러리를로드하고 두 개의 청크를 네 개의 750MB 라이브러리로 세분한다고 가정 해 보겠습니다. 그런 다음 두 개의 스레드가 있으며 각각은 더 많은 메모리 덩어리가 필요하며 나머지 영역은 더 이상 분리됩니다. 물론, 각각의 연속 블록의 정확한 중심에 배치되지는 않지만 (꽤 바보 같은 할당 전략이 될 것입니다.) 그럼에도 불구하고 이러한 모든 메모리 덩어리는 사용 가능한 메모리 공간을 세분화하여 많은 작은 조각으로.

600MB의 메모리를 사용할 수 있지만 실제로는 600MB가 연속 사용되지 않을 수 있습니다. 메모리를 사용할 수 있습니다. 따라서 하나의 600MB 할당이 거의 실패 할 경우 6 개의 100MB 할당이 성공할 수 있습니다.

할당 할 수있는 메모리 덩어리의 크기에는 고정 된 제한이 없습니다. 대답은 "의존합니다"입니다. 그것은 프로세스의 메모리 공간의 정확한 레이아웃에 달려 있습니다. 그러나 32 비트 시스템에서는 단일 할당으로 500MB 이상을 할당 할 수 없습니다.

관련 문제