Java MappedByteBuffers를 사용하여 "이 명령을 처리 할 수있는 충분한 저장 공간이 없다"는 이유는 무엇입니까?

StackOverflow https://stackoverflow.com/questions/1927123

  •  20-09-2019
  •  | 
  •  

문제

디스크 기반 파일을 사용하고있는 두 배의 배열과 처리 할 수있는 MappedByteBuffers 목록을 사용하고 있습니다. 이 질문 더 많은 배경. Java 1.5를 사용하여 Windows XP에서 실행 중입니다.

다음은 파일에 대한 버퍼를 할당하는 내 코드의 핵심 부분입니다 ...

try 
{
 // create a random access file and size it so it can hold all our data = the extent x the size of a double
 f = new File(_base_filename);
 _filename = f.getAbsolutePath();
 _ioFile = new RandomAccessFile(f, "rw");
 _ioFile.setLength(_extent * BLOCK_SIZE);
    _ioChannel = _ioFile.getChannel();

    // make enough MappedByteBuffers to handle the whole lot
 _pagesize = bytes_extent;
 long pages = 1;
 long diff = 0;
 while (_pagesize > MAX_PAGE_SIZE)
 {
  _pagesize  /= PAGE_DIVISION;
  pages *= PAGE_DIVISION;

  // make sure we are at double boundaries.  We cannot have a double spanning pages
  diff = _pagesize  % BLOCK_SIZE;
  if (diff != 0) _pagesize  -= diff;

 }

 // what is the difference between the total bytes associated with all the pages and the
 // total overall bytes?  There is a good chance we'll have a few left over because of the
 // rounding down that happens when the page size is halved
 diff = bytes_extent - (_pagesize  * pages);
 if (diff > 0)
 {
  // check whether adding on the remainder to the last page will tip it over the max size
  // if not then we just need to allocate the remainder to the final page
  if (_pagesize  + diff > MAX_PAGE_SIZE)
  {
   // need one more page
   pages++;
  }
 }

 // make the byte buffers and put them on the list
 int size = (int) _pagesize ;  // safe cast because of the loop which drops maxsize below Integer.MAX_INT
 int offset = 0;
 for (int page = 0; page < pages; page++)
 {
  offset = (int) (page * _pagesize );

  // the last page should be just big enough to accommodate any left over odd bytes
  if ((bytes_extent - offset) < _pagesize )
  {
   size = (int) (bytes_extent - offset);
  }

  // map the buffer to the right place 
     MappedByteBuffer buf = _ioChannel.map(FileChannel.MapMode.READ_WRITE, offset, size);

     // stick the buffer on the list
     _bufs.add(buf);
 }

 Controller.g_Logger.info("Created memory map file :" + _filename);
 Controller.g_Logger.info("Using " + _bufs.size() + " MappedByteBuffers");
    _ioChannel.close();
    _ioFile.close(); 
} 
catch (Exception e) 
{
 Controller.g_Logger.error("Error opening memory map file: " + _base_filename);
 Controller.g_Logger.error("Error creating memory map file: " + e.getMessage());
 e.printStackTrace();
 Clear();
    if (_ioChannel != null) _ioChannel.close();
    if (_ioFile != null) _ioFile.close();
 if (f != null) f.delete();
 throw e;
} 

두 번째 또는 세 번째 버퍼를 할당 한 후 제목에 언급 된 오류가 발생합니다.

나는 그것이 인접한 메모리와 관련이 있다고 생각 했으므로 다양한 크기와 페이지의 페이지로 시도했지만 전반적인 이점은 없습니다.

정확히 무엇을 하는가 "이 명령을 처리하기에 충분한 스토리지를 사용할 수 없습니다" 무엇을 의미하고 무엇이든 할 수 있습니까?

나는 MappedBytebuffers의 요점이 힙에 맞는 것보다 더 큰 구조물을 처리 할 수있는 능력이라고 생각했으며, 그들이 기억하는 것처럼 취급합니다.

단서가 있습니까?

편집하다:

아래 답변 (@ADSK)에 대한 응답으로 코드를 변경하여 한 번에 단일 활성 MAPPEDBYTEBUFFER 이상을 갖지 못했습니다. 현재 파일의 영역을 참조하면 기존 맵을 정크하고 새 맵을 만듭니다. 약 3 개의지도 작업 후에도 여전히 동일한 오류가 발생합니다.

MappedBytebuffers를 수집하지 않는 GC로 인용 된 버그는 여전히 JDK 1.5에서 문제가되는 것 같습니다.

도움이 되었습니까?

해결책

나는 MappedBytebuffers의 요점이 힙에 맞는 것보다 더 큰 구조물을 처리 할 수있는 능력이라고 생각했으며, 그들이 기억하는 것처럼 취급합니다.

아닙니다. 아이디어는 당신이 충분한 메모리가 있고 64 비트 JVM을 사용하고 있다는 가정하에 2 ** 31 더블 이상을 다룰 수 있도록하는 것입니다.

(나는 이것이 후속 질문이라고 가정합니다. 이 질문.)

편집하다: 더 많은 설명이 필요합니다.

많은 한계가 있습니다.

  1. Java는 그 근본적인 제한을 가지고 있습니다 length 배열의 속성 및 배열 인덱스는 유형이 있습니다. int. 이것은 사실과 결합했습니다 int 서명하고 배열은 음수 크기를 가질 수 없음 가장 큰 배열에 가질 수 있음을 의미합니다. 2**31 집단. 이 제한은 32 비트 및 64 비트 JVM에 적용됩니다. 그것은 Java 언어의 기본 부분입니다. char 값은에서 나옵니다 0 에게 65535.

  2. 32 비트 JVM 사용 A (이론적) 상한 2**32 JVM에서 주소를 지정할 수있는 바이트 수. 여기에는 전체 힙, 코드 및 사용하는 라이브러리 클래스, JVM의 기본 코드 코어, 매핑 버퍼에 사용되는 메모리가 포함됩니다. (사실, 플랫폼에 따라 OS 5월 당신에게 상당히 적습니다 2**32 주소 공간 인 경우 바이트.)

  3. Java Command Line에서 제공하는 매개 변수는 JVM이 얼마나 많은 힙 메모리를 결정합니다. 허용하다 사용할 응용 프로그램. 사용에 메모리 매핑 MappedByteBuffer 객체는 이것에 포함되지 않습니다.

  4. OS가 제공하는 메모리의 양은 (Linux/UNIX에) 구성된 총 스왑 공간, '프로세스'제한 등에 따라 다릅니다. 비슷한 한계는 아마도 창에 적용될 수 있습니다. 물론 호스트 OS가 64 비트 기능이 가능한 경우 64 비트 JVM 만 실행할 수 있으며 64 비트 유능한 하드웨어를 사용하고 있습니다. (펜티엄이 있다면 운이 좋지 않습니다.)

  5. 마지막으로, 시스템의 물리적 기억의 양이 작용합니다. 이론적으로는 JVM에 기계의 물리적 메모리보다 더 큰 힙 등을 사용하도록 요청할 수 있습니다. 실제로, 이것은 a입니다 나쁜 생각. 가상 메모리를 과도하게 할당하면 시스템이 삭감되고 응용 프로그램 성능이 바닥을 통과합니다.

테이크 아웃은 이것입니다.

  • 32 비트 JVM을 사용하는 경우 아마도 2**31 그리고 2**32 주소가 가능한 메모리의 바이트. 그것은 최대 사이에 충분한 공간입니다 2**29 그리고 2**30 배열 또는 매핑 버퍼를 사용하든 복식.

  • 64 비트 JVM을 사용하는 경우 단일 배열을 나타낼 수 있습니다. 2**31 더블스. 매핑 된 버퍼의 이론적 한계가 될 것입니다 2**63 바이트 또는 2**61 복식이지만 실질적인 한계는 기계가 가지고있는 물리적 기억의 양입니다.

다른 팁

메모리 매핑 파일은 32 비트 VM에서 주소 공간이 부족할 수 있습니다. 파일이 작은 덩어리에 매핑되고 바이트 버퍼에 더 이상 도달 할 수없는 경우에도 발생합니다. 그 이유는 GC가 버퍼를 풀기 위해 결코 시작하지 않기 때문입니다.

버그를 참조하십시오 http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6417205

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top