标签: mappedbytebuffer

在内存有限的系统上写入大文件时,如何避免mapFailed()错误

我刚刚在opensrc库代码中遇到一个错误,该代码分配了一个大缓冲区来修改大型flac文件,该错误只发生在使用Java 1.8.0_74 25.74-b02 32bit的具有3Gb内存的旧PC机上

最初我曾经只是分配一个缓冲区

ByteBuffer audioData = ByteBuffer.allocateDirect((int)(fc.size() - fc.position()));
Run Code Online (Sandbox Code Playgroud)

但有一段时间我有它

MappedByteBuffer mappedFile = fc.map(MapMode.READ_WRITE, 0, totalTargetSize);
Run Code Online (Sandbox Code Playgroud)

我(错误)的理解是映射缓冲区使用的内存少于直接缓冲区,因为整个映射缓冲区不必同时只在内存中使用的部分.但是这个答案说使用映射的字节缓冲区是一个坏主意,所以我不清楚它是如何工作的

Java Large File Upload抛出java.io.IOException:Map失败

完整的代码可以在这里看到

java mappedbytebuffer

8
推荐指数
1
解决办法
264
查看次数

使用 MappedByteBuffer 读取约 14GB 的大文件

我正在尝试解决 I/O 密集型的生产者消费者问题。生产者常量将数据附加到文件中,消费者从这个不断增长的文件中读取数据。文件大小通常以 GB 为单位(约 10GB)。

最初我尝试使用 BufferedOutputStream 和 BufferedInputStream 来读取数据并将数据写入文件。在上午 9:30 出现的数据突发期间,它占用了太多的系统 CPU %,例如 30-40%(必须是 I/O 的系统调用)。

查看内存映射文件可以加快速度。

    File fileToRead= new File("C:\\readThisFile.dat");
    FileChannel inChannel = new FileInputStream(fileToRead).getChannel();
    MappedByteBuffer buffer = inChannel.map(FileChannel.MapMode.READ_ONLY, 0, inChannel.size()); 
    byte[] data = new byte[(int)inChannel.size()];
    buffer.get(data);
Run Code Online (Sandbox Code Playgroud)

1) 由于文件 readThisFile.dat size() 大于 INTEGER.MAX 长度,inChannel.map() 会引发异常。

2)消费者如何使用超大文件的内存映射文件不断读取数据。消费者每次可以加载100MB并继续寻找更多数据?

3)是否有更快的解决方案,例如尝试除Java中的内存映射文件之外的其他方法?

java io file memory-mapped-files mappedbytebuffer

6
推荐指数
0
解决办法
2952
查看次数

将文件用于共享内存 IPC

在我的应用程序中,有一个进程将数据写入文件,然后响应接收到的请求,将通过网络向请求进程发送(一些)该数据。这个问题的基础是看当两个进程碰巧在同一台主机上时,我们是否可以加快通信速度。(就我而言,进程是 Java,但我认为这个讨论可以更广泛地适用。)

有一些项目使用 Java 的 FileChannel.map() 返回的 MappedByteBuffers 作为在同一主机上的 JVM 之间共享内存 IPC 的一种方式(参见 Chronicle Queue、Aeron IPC 等)。

加速同主机通信的一种方法是让我的应用程序使用其中一种技术为同主机通信提供请求-响应路径,结合现有的写入数据文件的机制,或者通过提供一种统一的通信和写入文件的方式。

另一种方法是允许请求进程直接访问数据文件。

我倾向于支持第二种方法 - 假设它是正确的 - 因为它更容易实现,并且似乎比为每个请求复制/传输数据副本更有效(假设我们没有替换现有的写入机制到文件)。

本质上,我想了解当两个进程访问同一个文件并使用它进行通信时究竟发生了什么,特别是 Java (1.8) 和 Linux (3.10)。

根据我的理解,如果两个进程同时打开同一个文件,它们之间的“通信”本质上将通过“共享内存”进行。

请注意,此问题与是否使用 MappedByteBuffer 对性能的影响无关 - 与读取和写入文件相比,使用映射缓冲区以及减少复制和系统调用似乎很可能会减少开销,但是可能需要对应用程序进行重大更改。

以下是我的理解:

  1. 当 Linux 从磁盘加载文件时,它会将该文件的内容复制到内存中的页面。该内存区域称为页面缓存。据我所知,无论使用哪种 Java 方法(FileInputStream.read()、RandomAccessFile.read()、FileChannel.read()、FileChannel.map())或本机方法读取文件,它都会执行此操作(关注“免费”并监视“缓存”值)。
  2. 如果另一个进程试图加载同一个文件(当它仍然驻留在缓存中时),内核会检测到这一点并且不需要重新加载文件。如果页面缓存已满,页面将被逐出 - 脏页面将被写回磁盘。(如果显式刷新到磁盘,并且定期使用内核线程刷新页面,页面也会被写回)。
  3. 缓存中已经有一个(大)文件是一个显着的性能提升,比基于我们使用哪些 Java 方法打开/读取该文件的差异要大得多。
  4. 如果使用 mmap 系统调用 (C) 或通过 FileChannel.map() (Java) 加载文件,则实质上文件的页面(在缓存中)会直接加载到进程的地址空间中。使用其他方法打开文件,将文件加载到不在进程地址空间中的页面中,然后读取/写入该文件的各种方法将一些字节从/向这些页面复制到进程地址空间中的缓冲区中. 避免该副本有明显的性能优势,但我的问题与性能无关。

所以总而言之,如果我理解正确的话——虽然映射提供了性能优势,但它似乎并没有提供任何我们尚未从 Linux 和页面缓存的性质中获得的“共享内存”功能。

所以,请让我知道我的理解在哪里。

谢谢。

java linux ipc memory-mapped-files mappedbytebuffer

6
推荐指数
1
解决办法
2660
查看次数

如何正确关闭MappedByteBuffer?

这是我正在运行的代码:

import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;

public class Main {
    public static void main(String[] args) throws Exception {
        String filePath = "D:/temp/file";
        RandomAccessFile file = new RandomAccessFile(filePath, "rw");

        try {
            MappedByteBuffer buffer = file.getChannel().map(FileChannel.MapMode.READ_WRITE, 0, 128);

            // Do something
            buffer.putInt(4);
        } finally {
            file.close();
            System.out.println("File closed");
        }

        System.out.println("Press any key...");
        System.in.read();

        System.out.println("Finished");
    }
}
Run Code Online (Sandbox Code Playgroud)

在按下某个键之前,我正在尝试在FAR Manager中手动删除该文件.但FAR说该文件被锁定:

 The process cannot access the file because it is being used by another process.
                     Cannot delete the file
                         D:\temp\file
                    Object is being opened …
Run Code Online (Sandbox Code Playgroud)

java randomaccessfile mappedbytebuffer java-9

5
推荐指数
2
解决办法
2289
查看次数

为什么这个"行数"程序在Java中变慢?使用MappedByteBuffer

为了尝试MappedByteBuffer(Java中的内存映射文件),我编写了一个简单的wc -l(文本文件行计数)演示:

int wordCount(String fileName) throws IOException {
    FileChannel fc = new RandomAccessFile(new File(fileName), "r").getChannel();
    MappedByteBuffer mem = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size());

    int nlines = 0;
    byte newline = '\n';

    for(long i = 0; i < fc.size(); i++) {
        if(mem.get() == newline)
            nlines += 1;
    }

    return nlines;
}
Run Code Online (Sandbox Code Playgroud)

我在大约15 MB(15008641字节)和100k行的文件上尝试了这个.在我的笔记本电脑上,它需要13.8 sec.为什么这么慢?

完整的类代码在这里:http://pastebin.com/t8PLRGMa

作为参考,我在C中写了相同的想法:http://pastebin.com/hXnDvZm6

它运行大约28毫秒,或490 times faster.

出于好奇,我还使用与Java中基本相同的算法和API编写了Scala版本.它运行10 times faster,这表明肯定有一些奇怪的事情发生.

更新:该文件由操作系统缓存,因此不会涉及磁盘加载时间.

我想使用内存映射来随机访问可能不适合RAM的较大文件.这就是为什么我不只是使用BufferedReader.

java performance nio mappedbytebuffer

5
推荐指数
1
解决办法
371
查看次数

内存映射文件在多进程方案中如何工作?

这个问题困扰我好几天了:

假设我有两个在同一台计算机上运行的进程(p_writep_read)。

  • 过程p_write用于写入/更新mmap文件。

  • 过程p_read是使用mmap文件的过程,换句话说,就是读取mmap文件。

我的假设是,p_write首先需要为mmap文件分配一个内存空间(堆外)(该空间使用Java MappedByteBufferAPI 自动映射到文件)。

我的问题是p_read如何从mmap文件读取?我现在的假设是,p_read还需要为要映射的mmap文件分配另一个相同大小的堆外空间,但这似乎是不正确的,因为在这种情况下,内存量需要加倍。

如果p_read不需要为要映射的mmap文件分配单独的内存空间,那么如何p_read知道文件映射到的正确内存地址p_write

更新1

我发现有一个更好的问题要问,或者您可以将其视为后续问题:如果FileChannel.map()两次调用,同一文件是否将两次映射到两个不同的内存空间?

// Scenario A: In single process

try (FileChannel fc = FileChannel.open(filePath, openOptions)) {
   // First call
   fc.map(MapMode.READ_ONLY, 0, SIZE_CONSTANT);
   // Second call
   fc.map(MapMode.READ_ONLY, 0, SIZE_CONSTANT);
}
Run Code Online (Sandbox Code Playgroud)

// Scenario B: In two processes

// in first process
try (FileChannel fc = FileChannel.open(filePath, openOptions)) {
   // First …
Run Code Online (Sandbox Code Playgroud)

java memory filechannel memory-mapped-files mappedbytebuffer

5
推荐指数
0
解决办法
246
查看次数

Java,为什么从MappedByteBuffer读取比从BufferedReader读取慢

我尝试从可能很大的文件中读取行。

为了获得更好的性能,我尝试使用映射文件。但是当我比较性能时,我发现映射文件方式甚至比我读取的速度慢一点BufferedReader

public long chunkMappedFile(String filePath, int trunkSize) throws IOException {
    long begin = System.currentTimeMillis();
    logger.info("Processing imei file, mapped file [{}], trunk size = {} ", filePath, trunkSize);

    //Create file object
    File file = new File(filePath);

    //Get file channel in readonly mode
    FileChannel fileChannel = new RandomAccessFile(file, "r").getChannel();

    long positionStart = 0;
    StringBuilder line = new StringBuilder();
    long lineCnt = 0;
    while(positionStart < fileChannel.size()) {
        long mapSize = positionStart + trunkSize < fileChannel.size() ? trunkSize : fileChannel.size()  - positionStart …
Run Code Online (Sandbox Code Playgroud)

java io mappedbytebuffer

1
推荐指数
1
解决办法
1790
查看次数