MappedByteBuffer - BufferOverflowException

Posted

技术标签:

【中文标题】MappedByteBuffer - BufferOverflowException【英文标题】: 【发布时间】:2017-07-15 06:41:15 【问题描述】:

我正在使用 MappedByteBuffer 将记录写入文件。下面是我的代码。当我增加要写入的 numberOfRows 时,它会抛出 BufferOverflowException。它适用于 1000 万个 numberOfRows。如果我将 numberOfRows 增加到 1 亿,它会抛出 BufferOverlowException!?

public static void writeOneFile() throws IOException
     File file = File.createTempFile("outputfile", ".txt", new File("C:\\Data\\Output"));
     //f.delete();
     RandomAccessFile fileAccess = new RandomAccessFile(file, "rw");
     FileChannel fileChannel = fileAccess.getChannel();

     long bufferSize = (long) (Math.pow(10240, 2));//(long)(Math.pow(30720, 2));//(long) (Math.pow(1024, 2));//(long)Integer.MAX_VALUE;
     MappedByteBuffer mappedBuffer = fileChannel.map( FileChannel.MapMode.READ_WRITE, 0, bufferSize );

     long startPosMappedBuffer = 0;
     long million = 1000000; 
     long numberOfRows = million * 100; //million * 200 ;//1000;//million * 200 ; //200 million

     long startTime = System.currentTimeMillis();

     long counter = 1;
     //byte[] messageBytes = (counter+"").getBytes(Charset.forName("UTF-8"));
     //long bufferSize = (counter + "\n").getBytes(Charset.forName("UTF-8")).length * 1000;
     while(true)
              
         if( !mappedBuffer.hasRemaining() )
         
             startPosMappedBuffer += mappedBuffer.position();
             mappedBuffer = fileChannel.map( FileChannel.MapMode.READ_WRITE, startPosMappedBuffer, bufferSize );
         
         mappedBuffer.put( (counter + System.lineSeparator()).getBytes(Charset.forName("UTF-8")) ); //+ System.lineSeparator() //putLong( counter ); // ); 
         //mappedBuffer.rewind();

         counter++;
         if( counter > numberOfRows )
             break; 
     
     fileAccess.close();
     long endTime = System.currentTimeMillis();
     long actualTimeTaken = endTime - startTime;
     System.out.println( String.format("No Of Rows %s , Time(sec) %s ", numberOfRows, actualTimeTaken / 1000f) ) ;  
 

关于问题的任何提示?

编辑 1:异常问题已解决并回答如下。

编辑 2:关于性能的最佳选择。

@EJP:这里是在 BufferedOutputStream 周围使用 DataOutputStream 的代码。

static void writeFileDataBuffered() throws IOException
        File file = File.createTempFile("dbf", ".txt", new File("C:\\Output"));
        DataOutputStream out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream( file )));
        long counter = 1;
        long million = 1000000;
        long numberOfRows = million * 100;
        long startTime = System.currentTimeMillis();
        while(true)
            out.writeBytes( counter + System.lineSeparator() );
            counter++;
            if ( counter > numberOfRows )
                break;
        
        out.close();
        long endTime = System.currentTimeMillis();
        System.out.println("Number of Rows: "+ numberOfRows + ", Time(sec): " + (endTime - startTime)/1000f);
    

....... 谢谢

【问题讨论】:

MappedByteBuffers 对性能的影响几乎为零。您应该从 DataOutputStream 周围的 BufferedOutputStream 开始,然后看看您是否真的有 I/O 性能问题。 @EJP:感谢您的评论。我已经尝试过两种方法来得出最佳方法。我对 1 亿条记录的结果是:DataOutputStream--> 行数:100000000,时间(秒):31.707 MappedByteBuffer--> 行数:100000000,时间(秒):16.576 我可以知道投反对票的原因吗?是问题的范围变化吗? 但是你没有提供我建议的配置的时间。 @EJP:我用 BufferedOutputStream 周围的 DataOuputStream 代码编辑了这个问题。是否符合您的预期? 【参考方案1】:

经过一些后台工作,我找到了根本原因。我声明的 bufferSize 小于我正在写入的内容长度。

1亿条记录所需的字节数为:988888898,而带有(long) (Math.pow(10240, 2))的bufferSize为:104857600。bufferSize短884031298字节。如异常所示,这是导致问题的原因。

bufferSize 也可以用作 Integer.MAX_VALUE 而不是计算正在写入的内容大小。虽然这会增加文件大小,但根据我的试运行结果,它不会对程序的性能产生任何影响。

…………

谢谢

【讨论】:

以上是关于MappedByteBuffer - BufferOverflowException的主要内容,如果未能解决你的问题,请参考以下文章

通道Channel获取四种方法

神奇的MappedByteBuffer

如何正确关闭 MappedByteBuffer?

MappedByteBuffer - BufferOverflowException

MappedByteBuffer - 页面到物理内存的映射

使用 java.nio.MappedByteBuffer 时防止 OutOfMemory