`
chrhust
  • 浏览: 5640 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
文章分类
社区版块
存档分类
最新评论

【转】关于MappedByteBuffer资源释放问题

阅读更多
JDK1.4中加入了一个新的包:NIO(java.nio.*)。这个库最大的功能(我认为)就是增加了对异步套接字的支持。其实在 其他语言中,包括在最原始的SOCKET实现(BSD SOCKET),这是一个早有的功能:异步回调读/写事件,通过选择器动态选择感兴趣的事件,等等。
先谈谈操作系统的内存管理。一般操作系统的内存分两部分:物理内存;虚拟内存。虚拟内存一般使用的是页面映像文件,即硬盘中的某个(某些)特殊的文件.操作系统负责页面文件内容的读写,这个过程叫"页面中断/切换"。
MappedByteBuffer也是类似的,你可以把整个文件(不管文件有多大)看成是一个ByteBuffer。这是一个很好的设计,除了令人头疼的一点在后面会讲到。
java.lang.Object
   java.nio.Buffer
      java.nio.ByteBuffer
          java.nio.MappedByteBuffer
MappedByteBuffer是一个比较方便使用的类。其内容是文件的内存映射区域。映射的字节缓冲区是通过 FileChannel.map 方法创建的。映射的字节缓冲区和它所表示的文件映射关系在该缓冲区本身成为垃圾回收缓冲区之前一直保持有效。此类用特定于内存映射文件区域的操作扩展 ByteBuffer 类。 这个类本身的设计是不错的,比直接操作byte[]方便多了。
ByteBuffer有两种模式:直接/间接。间接模式最典型(也只有这么一种)的就是HeapByteBuffer,即操作堆内存(byte [])。但是内存毕竟有限,如果我要发送一个1G的文件怎么办?不可能真的去分配1G的内存.这时就必须使用"直接"模式,即 MappedByteBuffer,文件映射。
在JDK API文档中这样描述的:
全部或部分映射的字节缓冲区可能随时成为不可访问的,例如,如果我们截取映射的文件。试图访问映射的字节缓冲区的不可访问区域将不会更改缓冲区 的内容,并导致在访问时或访问后的某个时刻抛出未指定的异常。因此强烈推荐采取适当的预防措施,以避免此程序或另一个同时运行的程序对映射的文件执行操作 (读写文件内容除外)。
MappedByteBuffer只能通过调用FileChannel的map()取得,再没有其他方式.但是令人奇怪的是,SUN提供了map()却没有提供unmap().这样会导致什么后果呢?
这样,问题就出现了。通过MappedByteBuffer实现文件复制功能非常容易,可以用以下方法来实现。
   //文件复制
 
 public void copyFile(String filename,String srcpath,String destpath)throws IOException {
    File source = new File(srcpath+"/"+filename);
    File dest = new File(destpath+"/"+filename);
     FileChannel in = null, out = null;
     try { 
      in = new FileInputStream(source).getChannel();
      out = new FileOutputStream(dest).getChannel();
      long size = in.size();
      MappedByteBuffer buf = in.map(FileChannel.MapMode.READ_ONLY, 0, size);
      out.write(buf);
      in.close();
      out.close();
      source.delete();//文件复制完成后,删除源文件
     }catch(Exception e){
      e.printStackTrace();
     } finally {
      in.close();
      out.close();
     }
   }

但是如果要实现文件文件复制完成后,删除源文件,以上方法就有问题。因为在source.delete()时,会返回false,删除失败,主 要原因是变量buf仍然有源文件的句柄,文件处于不可删除状态。既然MappedByteBuffer是从FileChannel中map()出来的,为 什么它又不提供unmap()呢?SUN自己也没有讲清楚为什么。O'Reilly的<<Java NIO>>中说是因为"安全"的原因,但是到底unmap()会怎么不安全,作者也没有讲清楚。
在sun网站也有相应的BUG报告:bug id:4724038链接为http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4724038,但是sun自己不认为是BUG,而只是一个RFE(Request For Enhancement),有待改进。
好在有个叫bellomi的网友提出了一个解决方法,我也测试过,可以实现期望的功能。具体实现代码如下:
   public static void clean(final Object buffer) throws Exception {
         AccessController.doPrivileged(new PrivilegedAction() {
             public Object run() {
             try {
                Method getCleanerMethod = buffer.getClass().getMethod("cleaner",new Class[0]);
                getCleanerMethod.setAccessible(true);
                sun.misc.Cleaner cleaner =(sun.misc.Cleaner)getCleanerMethod.invoke(buffer,new Object[0]);
                cleaner.clean();
             } catch(Exception e) {
                e.printStackTrace();
             }
                return null;}});
         
}

不知道为什么SUN不提供ByteBuffer的派生。毕竟这是一个很实用的类,如果允许派生,那么我就可以操作的就不仅仅限于堆内存和文件了,我可以扩展到任何存储设备。
分享到:
评论

相关推荐

    IPC.rar_IPC_java i_java ipc_java共享内存_共享内存

    5. **释放资源**:在完成通信后,记得取消映射并关闭文件通道,以释放系统资源。 在标签中提到的“i java_ipc java共享内存”可能是指Java接口(Interface)在IPC中的应用,接口可以作为进程间通信的一种约定,定义...

    java-Operation-On-Files.rar_operation

    - 总是在使用后关闭流,以释放系统资源,避免资源泄漏。可以使用try-with-resources语句自动关闭流。 - 操作文件时要考虑并发问题,特别是在多线程环境下。 - 对于可能出现的异常,如文件不存在、权限不足等,要...

    Tech Salon 008 - 分布式监控系统实践.6cf354e0-39bc-11e6-bce6-b7dd80bb9649.

    7. **内存分析**:关注MessageTree的内存占用,以及如何有效地管理和释放MappedByteBuffer,防止内存泄漏。 8. **接收与分析组件**:包括接收线程、发送线程、消息队列和服务器,它们共同负责数据的收集、处理和...

    1K空间快速读写文件工具类

    在编写这样的工具类时,需要注意线程安全、异常处理、资源释放等方面的问题,以确保代码的健壮性和效率。 综上所述,"1K空间快速读写文件工具类"是一个利用Java技术进行高效文件操作的实现,它通过各种优化手段,如...

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

    // 当缓冲区不再需要时,调用clear()或compact()释放内存资源 buffer.clear(); fileChannel.close(); randomAccessFile.close(); } catch (Exception e) { e.printStackTrace(); } } } ``` 在上面的代码中...

    Java多线程读取大文件

    ### 五、异常处理和资源释放 在实现过程中,还需要考虑异常处理和资源的及时释放。例如,当线程遇到错误时,应有适当的处理机制,避免程序崩溃。同时,完成文件读取后,必须关闭打开的文件通道和释放内存映射资源,...

    JAVA IO-NIO 详解

    - **释放资源**: 使用完毕后需正确释放资源,避免内存泄漏。 - **性能考量**: 对于大文件,可能会影响性能,需要根据实际情况评估。 #### 七、Selector使用 **1. 创建Selector** - **Selector**: 用于监控多个...

    IO文件读取

    完成文件操作后,记得关闭打开的流,以释放资源。Java 7引入的try-with-resources语句可以简化这个过程: ```java try (BufferedReader br = new BufferedReader(new FileReader("example.txt"))) { // 读取操作...

    读大文件Java

    将大文件分成小块读取,每读完一块就处理并释放,可以有效地控制内存占用。 9. **监控和异常处理**: 在处理大文件时,务必注意监控系统资源使用情况,如CPU、内存和磁盘I/O。同时,妥善处理可能出现的...

    简要分析Java多进程编程的并发控制

    Java多进程编程中的并发控制主要关注的是如何在多个独立的程序之间有效地共享资源,特别是内存。在Java中,虽然直接的内存管理不是语言的核心特性,但是通过特定的API,我们仍然可以实现进程间的内存共享。这里我们...

    androidtxtfile_android源码_

    4. **关闭流**:最后,别忘了关闭`FileInputStream`和`ByteArrayOutputStream`以释放资源。 ```java fis.close(); baos.close(); ``` 在这个过程中,`ByteArrayOutputStream`的`write()`方法会将输入的整数(代表...

    J2SE.development.code.MemMapFile.rar_Java编程_Java_

    映射的内存不会随着`MappedByteBuffer`实例的垃圾收集而释放,因此在不再需要时,必须调用`channel.close()`来关闭`FileChannel`,以确保释放资源。 总结来说,J2SE应用MemMapFile开发是利用Java NIO的内存映射...

    java大文件读取-乔乐共享

    对于超过几百兆甚至更大的文件,传统的逐行读取方法可能会导致性能问题或者内存溢出。本文将详细介绍如何在Java中有效地处理大文件读取,并给出具体示例。 #### 二、Java大文件读取方法概述 在Java中,处理大文件...

    java io一些探讨

    - `close()`: 关闭流并释放其占用的系统资源。 **2. 文件流** - `FileInputStream`和`FileOutputStream`用于读写文件中的数据。 - `FileReader`和`FileWriter`用于读写文件中的文本数据。 **3. `...

    java技术分享

    - **入门级介绍**:文章首先介绍了如何通过反射获取`Unsafe`对象,接着探讨了如何实现类似C语言中的`sizeof`函数的功能,并演示了如何在非堆内存中分配和释放内存。 - **注意事项**: - 《Unsafe Pointer Chasing》...

    mmapcom:内存映射文件实用程序库,用于存放更大尺寸的文件

    `mmapcom-master`可能是项目源码的主分支,包含了库的源代码、测试用例、文档和其他资源。如果你打算使用或研究这个库,可以从这个压缩包中解压并查看项目结构,了解其内部实现细节和如何在自己的项目中集成使用。...

    Java的File类文件读写以及图片下载的总结

    在实际开发中,为确保资源有效释放,建议使用`try-with-resources`语句处理流。同时,文件操作时要考虑到异常处理,确保程序的健壮性。此外,对于大型文件,考虑使用`nio`(非阻塞I/O)提供的更高效的方法,如`...

    Java中channel用法总结

    例如,`isOpen()`用于检查通道是否仍处于开启状态,而`close()`方法则用于关闭通道,释放其占用的资源。这两个方法都定义在`Channel`接口中。 2. **Channel的常见类型**: - `FileChannel`:用于文件读写,可以...

Global site tag (gtag.js) - Google Analytics