`
newslxw
  • 浏览: 213923 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

MappedByteBuffer小结

阅读更多

java的内存映射文件有如下特点:

 

1,使用虚拟内存,因此分配(map)的内存大小不受JVM的-Xmx参数限制,但是也是有大小限制的,首先他理论上不能超过Integer.MAX_VALUE也就是32位操作系统的2G,其次,其实际值在不用操作系统还不一样,在win7 32位操作系统下,他不能超过1.5G,具体多少,没测出来,也不知道什么原因。

 

2, 对应读大文件,当文件超出1.5G限制是,可以重新MAP下,通过POSITION参数来获取文件后面的内容。

 

3,它的读取和来回读取要不普通IO快的多,但是单纯的写入还不如普通I/O的一般速度。此结论来自以下测试代码

package com.chat;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileChannel.MapMode;


public class FileChannelStudy
{


    static String filename1 = "d:\\work\\code\\filechannelstudy.txt";
    static String filename2 = "d:\\work\\code\\file.txt";
    static String content = "abcdefghijk\r\n";
    static long size =  1024000000l;
    static long num = size / 10*6;
    static long startT = 0;
    static long endT = 0;
    
    public static void setStartT()
    { mbb = null;
                    if(cnt %50 == 0) 
                        {
                        System.gc();
                        System.out.println("call gc");
                        } 
        startT = System.currentTimeMillis();
    }
    
    public static long ellipseT()
    {
        endT = System.currentTimeMillis();
        long consumeT = endT - startT;
        System.out.println("consume time :"+ consumeT/1000 + " second");
        return consumeT / 1000;
    }
    
    /**
     * @param args
     * @throws IOException 
     */
    public static void main(String[] args) throws IOException
    {
       // readFile1();
        createFile(true);
        preparedFile1();
        preparedFile2();
        
    }
    
    public static void createFile(boolean bReCreate) throws IOException
    {
        if(!bReCreate)
        {
            File f = new File(filename1);
            if(!f.exists()) f.createNewFile();
            f = new File(filename2);
            if(!f.exists()) f.createNewFile();
        }
        else
        {
            File f = new File(filename1);
            if(f.exists()) f.delete();
            f.createNewFile();
            f = new File(filename2);
            if(f.exists()) f.delete();
            f.createNewFile();
        }
    }
    
    public static void preparedFile2() throws IOException
    {
        
        BufferedOutputStream bo = new BufferedOutputStream(new FileOutputStream(filename2));
        try
        {
            System.out.println("fill file by io");
            setStartT();
            for (int i = 0; i < num; i++)
            {
                bo.write(content.getBytes());
            }
            ellipseT();
        }
        finally
        {
            if(bo != null) bo.close();
        }
    }
    
    public static void preparedFile1() throws IOException
    {
        long mapsize = content.getBytes().length*1000000*100;
        long position = 0;
        FileChannel ch = new RandomAccessFile(filename1,"rw").getChannel();
        MappedByteBuffer mbb = ch.map(MapMode.READ_WRITE, position, mapsize);
        int cnt = 0;
        try
        {
            System.out.println("fill file by nio");
            setStartT();
            for (int i = 0; i < num; i++)
            {
                if(mbb.remaining() < content.getBytes().length) 
                {
                    cnt ++;
                    position += mbb.position();
                    mbb = null;
                    if(cnt %50 == 0) 
                        {
                        System.gc();
                        System.out.println("call gc");
                        }
                    mbb =  ch.map(MapMode.READ_WRITE, position, mapsize);
                }
                mbb.put(content.getBytes());
            }
            ellipseT();
        }
        finally
        {
            if(ch != null) ch.close();
        }
    }
    
    public static void readFile1() throws IOException
    {
        long mapsize = content.getBytes().length*1000000;
        long position = 0;
        //long rper = 2000000000;
        long rper =   1300000000;
        FileChannel ch = new RandomAccessFile(filename1,"rw").getChannel();
        MappedByteBuffer mbb = ch.map(MapMode.READ_WRITE, 0, rper);
        int rs = 102400;
        byte dst[] = new byte[rs];
        int cnt = 0;
        while(mbb.hasRemaining())
        {
            ByteBuffer bb = mbb.get(dst);
            cnt ++;
            if(cnt %50 == 0) System.out.println(bb.toString());
        }
    }

}
 

4,谁然FileOutputStream也有channel功能,但是如果要用内存映射文件方式写文件,则只能使用RandomAccessFile,视乎是因为写时就有读,所以只能用它。

 

5, 他跟其他ByteBuffer不一样的地方,其他ByteBuffer需要用channel.write/read来写入/读取目标的数据,而MappedByteBuffer直接就是对于目标,它的修改会自动写入到磁盘中,除非你设定了PRIVATE。

 

6, 内存溢出问题,除了尺寸限制,在写大文件时,由于要不停的重新map,会导致内存溢出,或者说gc来不及回收内存,如上面程序,如果把prepareFile1中的

 mbb = null;
                    if(cnt %50 == 0) 
                        {
                        System.gc();
                        System.out.println("call gc");
                        }

 代码删除,则在3G左右就会报内存溢出;如果只保留mbb=null;则在5G左右报内存溢出,都保留则不报内存溢出。因此需要手工运行System.gc().

 

 

7, 对于中文读写,需要转码。

    当然原来io也需要转码,不过有InputStreamReader中可以指定字符集因此可以不自己写代码。

    如果不转码,则用UE等工具打开文件看到的是乱码,但是用java的MappedByteBuffer读取处理还是中文。

    转码代码:

 

 public static ByteBuffer getBytes(String str)
    {// 将字符转为字节(编码)
        Charset cs = Charset.forName("GBK");
        ByteBuffer bb = ByteBuffer.wrap(str.getBytes(cs));
        return bb;
    }

    public static String getChars(ByteBuffer bb)
    {// 将字节转为字符(解码)
        Charset cs = Charset.forName("GBK");
        bb.flip();
        CharBuffer cb = cs.decode(bb);

        return cb.toString();
    }
 

 

分享到:
评论

相关推荐

    深入浅出MappedByteBuffer.pdf

    《深入浅出MappedByteBuffer》这篇文章主要探讨了Java NIO中MappedByteBuffer这一高效处理大文件的机制,以及与其相关的计算机内存管理概念。首先,我们来详细理解一下这些知识点。 内存管理是计算机系统的重要组成...

    Bug ID 4724038 (fs) Add unmap method to MappedByteBuffer

    Bug ID 4724038 (fs) Add unmap method to MappedByteBuffer

    文件分割和合并(您的文件大的不能传输怎么办?)

    本人初学c++,写了一个小软件,能把大文件分割问小文件,然后可以统国网络传输,到了网络另一端,再用此软件拼接! 希望用过的人能提宝贵意见! 13521825644 qq 362192302

    【IT十八掌徐培成】Java基础第27天-01.MappedMemoryBuffer-文件内存映射缓冲区.zip

    另外,内存映射文件不适合频繁的小规模写操作,因为每次写操作都会导致整个缓冲区在内存中变为脏,可能增加不必要的同步开销。 总的来说,Java的MappedByteBuffer是处理大文件的强大工具,它利用了操作系统的内存...

    commons-mmf.rar_java nio_java共享内存_共享内存

    在Java中,可以通过`java.nio.MappedByteBuffer`类来实现共享内存功能,这被称为内存映射文件(Memory-Mapped File,MMF)。 `MappedByteBuffer`是NIO中的一种特殊缓冲区,它将文件的一部分映射到内存中,使得文件...

    java读取大文件

    为了有效地读取大文件,可以使用缓冲区(Buffer)和内存映射文件(MappedByteBuffer)技术。下面将详细解释如何使用这些技术以及代码中的关键部分。 1. **缓冲区(Buffer)**: Java中的缓冲区是用于提高数据读写...

    java8源码-netty-learn:这是一个用于netty学习的工程

    MappedByteBuffer DirectByteBuffer HeapByteBuffer ShortBuffer IntBuffer LongBuffer FloatBuffer DoubleBuffer CharBuffer Selector选择器 Selector的作用就是配合一个线程来管理多个channel,获取这些channel上...

    java读取超大文本文件

    对于需要随机访问或文件特别大的情况,推荐使用`RandomAccessFile`和`FileChannel`的组合,特别是利用`MappedByteBuffer`进行内存映射文件读取。这种方式能够显著提高文件的读取速度,因为数据直接从磁盘映射到内存...

    Java NIO 应用使用内存映射文件实现进程间通信

    在Java NIO中,内存映射文件(MappedByteBuffer)是一个重要的特性,它允许将文件直接映射到内存中,以便于快速访问和修改文件内容。这一特性不仅提高了读写效率,而且还能用于进程间通信(IPC)。 内存映射文件的...

    读取文件数据并解析成bean实体类

    在IT行业中,文件数据的处理是一项常见的任务,特别是在数据交换和存储时。"读取文件数据并解析成bean实体类"这一主题涉及到的核心知识点主要包括文件操作、数据解析以及对象映射。下面将详细阐述这些概念及其应用。...

    java csv大数据量导出(千万级别,不会内存溢出)

    通过MappedByteBuffer,我们可以让操作系统负责数据的缓存和页面交换,这在处理大文件时能显著降低内存使用。 在实际生产环境中,为了确保稳定性,还需要考虑错误处理和重试机制。例如,当某个线程在处理数据时发生...

    文件高速传输读写 客户端服务端

    本主题聚焦于Java平台下如何实现高效的文件操作,特别是利用内存映射(MappedByteBuffer)进行读写和通过网络进行文件传输。以下是相关的知识点详解: 1. **内存映射文件(MappedByteBuffer)**: 内存映射文件是...

    java 中Buffer源码的分析

    另外,虽然 MappedByteBuffer 在逻辑上应该是 DirectByteBuffer 的子类,而且 MappedByteBuffer 的内存的 GC 和直接内存的 GC 类似(和堆 GC 不同),但是分配的 MappedByteBuffer 的大小不受 -XX:...

    java 一个文件变成多个小文件

    另外,如果文件非常大,可以考虑使用内存映射文件(`MappedByteBuffer`)或NIO(New I/O)来进一步优化性能。 以上就是用Java将一个文件拆分为多个小文件的基本步骤和相关知识点。在实际应用中,根据具体需求,可能...

    NIO按行读取数据

    - **MappedByteBuffer**:文件映射缓冲区,它允许将文件的一部分直接映射到内存,从而提供快速的文件访问。 2. **按行读取的实现**: - 类`NioReader`初始化时,创建了一个`FileInputStream`和`FileChannel`对象...

    关于断点续传的相关资料,包含源代码

    MappedByteBuffer buffer = remoteChannel.map(FileChannel.MapMode.READ_ONLY, remoteChannel.position(), blockSize); if (buffer.limit() == 0) break; localChannel.write(buffer); } // 关闭文件通道 ...

    j2se项目源码及介绍_last指令

    函数原型 private MappedByteBuffer mappedFile2Buffer(File f) throws Exception 函数说明 把日志文件映射成内存缓冲 参数说明 @param File f日志文件 返回说明 @return MappedByteBuffer 内存映射缓冲。 异常说明 ...

    Java内存映射 大文件轻松处理

    对于小文件,由于页对齐可能导致内存浪费。此外,大文件映射可能导致内存占用过高,尤其是在内存有限的环境中。因此,使用内存映射文件时应谨慎评估文件大小和系统资源。 总之,Java的内存映射文件功能为处理大文件...

    Java中用内存映射处理大文件的实现代码

    FileChannel提供了map()方法,可以将文件的一部分或全部映射到Java虚拟机的内存中,形成一个MappedByteBuffer对象。这样,对MappedByteBuffer的操作实际上就是对文件的直接操作,无需频繁地进行磁盘I/O,大大提高了...

    JAVA多线程断电续传下载程序

    `FileChannel`提供了随机读写文件的能力,而`MappedByteBuffer`则可以将文件的一部分映射到内存,使得对文件的操作就像操作普通数组一样方便。通过比较已下载的缓冲区与目标文件的校验值,可以判断下载是否完整,...

Global site tag (gtag.js) - Google Analytics