代码之家  ›  专栏  ›  技术社区  ›  Simon

为什么我使用Java MappedBytebuffer获得“没有足够的存储空间来处理此命令”?

  •  2
  • Simon  · 技术社区  · 16 年前

    我有一个非常大的double数组,我正在使用一个基于磁盘的文件和一个mappedbytebuffer分页列表来处理它,请参阅 this question 更多背景资料。我使用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;
    } 
    

    在分配第二个或第三个缓冲区后,我得到了标题中提到的错误。

    到底是什么 “存储空间不足,无法处理此命令” 我的意思是,如果有什么,我能做些什么?

    有什么线索吗?

    编辑:

    GC引用的错误没有收集MappedBytebuffer在JDK1.5中似乎仍然是个问题。

    2 回复  |  直到 9 年前
        1
  •  3
  •   Community Mohan Dere    9 年前

    我认为MappedBytebuffer的要点是能够处理比堆中容纳的结构更大的结构,并将它们视为内存中的结构。

    (我假设这是一个后续问题 this question .)

    有许多限制在起作用。

    1. Java有一个基本的限制,即 length int . 这,再加上 int 是有符号的,并且数组的大小不能为负,这意味着最大的数组可以具有负大小 2**31 char 价值观来自 0 65535 .

    2. 使用32位JVM会将 2**32 JVM可寻址的字节数。这包括整个堆、您的代码和您使用的库类、JVM的本机代码核心、用于映射缓冲区的内存。。。一切(事实上,根据您的平台,操作系统 也许 2**32 字节(如果是地址空间)

    3. 您在java命令行上给出的参数决定JVM将使用多少堆内存 要使用的应用程序。使用映射到的内存 MappedByteBuffer

    4. 操作系统将提供给您的内存量(取决于Linux/UNIX)取决于配置的交换空间总量、“进程”限制等。类似的限制可能适用于Windows。当然,如果主机操作系统支持64位,并且您使用的是支持64位的硬件,那么您只能运行64位JVM(如果你有一个奔腾,你显然是运气不好。)

    5. 最后,系统中的物理内存量开始发挥作用。从理论上讲,您可以要求JVM使用比您机器的物理内存大很多倍的堆等。在实践中,这是一个很好的例子 坏主意

    外卖是这样的:

    • 2**31 2**32 2**29 2**30 双倍,无论使用数组还是映射缓冲区。

    • 如果使用64位JVM,则可以表示单个 双打。映射缓冲区的理论极限为 2**63 字节或 2**61 两倍,但实际限制大致相当于您的机器拥有的物理内存量。

        2
  •  1
  •   adsk    16 年前

    当内存映射文件时,32位VM中的地址空间可能会用完。即使文件被映射成小块,并且这些ByteBuffer不再可访问,也会发生这种情况。原因是GC从来不会启动以释放缓冲区。

    http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6417205

    推荐文章