zoukankan      html  css  js  c++  java
  • 释放 MappedByteBuffer映射的内存

    对于MappedByteBuffer映射的文件,直接调用删除方法是无法删掉的。原因就是这部分内存的回收靠的是垃圾回收机制。

    而垃圾回收的时间是我们无法控制的,这就导致了文件始终被占用。看一个例子:

    FileInputStream fis = null;  
            File f = new File("a.txt");  
            try {  
                fis = new FileInputStream(f);  
                FileChannel fc = fis.getChannel();  
      
                // 把文件映射到内存  
                MappedByteBuffer bb = fc.map(FileChannel.MapMode.READ_ONLY, 0,  
                        (int) fc.size());  
      
                // TODO  
      
                fc.close();  
                fis.close();  
            } catch (FileNotFoundException ex) {  
                System.err.println("Error! " + ex.getMessage());  
                System.exit(2);  
            } catch (IOException e) {  
                System.err.println("Error! " + e.getMessage());  
                System.exit(3);  
            }  
      
            // 删除文件  
            boolean deleted = f.delete();  
            if (!(deleted)) {  
                System.err.println("Could not delete file " + f.getName());  
            }  
    

     删除文件失败!原因是没有释放内存。

    究其原因,FileChannel在调用了map方法,进行内存映射得到MappedByteBuffer,但是没有提供unmap方法(),释放内存。事实上,unmap方法是在FileChannelImpl类里实现的,是个私有方法。在finalize延迟的时候,unmap方法无法调用,在删除文件的时候就会因为内存未释放而失败。不过可以通过显示的调用unmap方法来释放内存。

    以下代码则可以保证可以成功删除文件:

    try {  
                File f = File.createTempFile("Test", null);  
                f.deleteOnExit();  
                RandomAccessFile raf = new RandomAccessFile(f, "rw");  
                raf.setLength(1024);  
                FileChannel channel = raf.getChannel();  
                MappedByteBuffer buffer = channel.map(  
                        FileChannel.MapMode.READ_WRITE, 0, 1024);  
                channel.close();  
                raf.close();  
                // 加上这几行代码,手动unmap  
                Method m = FileChannelImpl.class.getDeclaredMethod("unmap",  
                        MappedByteBuffer.class);  
                m.setAccessible(true);  
                m.invoke(FileChannelImpl.class, buffer);  
                if (f.delete())  
                    System.out.println("Temporary file deleted: " + f);  
                else  
                    System.err.println("Not yet deleted: " + f);  
            } catch (Exception ex) {  
                ex.printStackTrace();  
            }  
    

     其实最终都是调用了Cleaner类的,clean方法。

    我们从FileChannelImpl的unmap方法来入手

        private static void unmap(MappedByteBuffer bb) {  
            Cleaner cl = ((DirectBuffer)bb).cleaner();  
            if (cl != null)  
                cl.clean();  
        }  
    

     这是一个私有方法,调用了Cleaner的clean方法来释放内存,所以我们也可以直接在代码里使用以上代码来释放内存。

  • 相关阅读:
    bzoj1455-罗马游戏
    bzoj1206-[HNOI2005]虚拟内存
    bzoj2762-[JLOI2011]不等式组
    bzoj2729-[HNOI2012]排队
    [模板] 高精度加/减/乘
    bzoj1013-[JSOI2008]球形空间产生器
    bzoj1002-[FJOI2007]轮状病毒
    什么是Redis缓存穿透、缓存雪崩和缓存击穿
    CentOS 7 中英文桌面安装步骤详细图解
    Redis数据操作
  • 原文地址:https://www.cnblogs.com/swbzmx/p/5992592.html
Copyright © 2011-2022 走看看