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

     

    https://www.cnblogs.com/swbzmx/p/5992592.html

    对于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方法来释放内存,所以我们也可以直接在代码里使用以上代码来释放内存。

    __________________________________________________________________________________________________________________________

    Java之nio MappedByteBuffer的资源释放问题

    http://t.zoukankan.com/zolo-p-5849320.html


    使用nio的MappedByteBuffer映射内存, 在最后执行File.delete()方法的时候, 返回false, 即文件没有被删除.
    原因是MappedByteBuffer在内存中也会创建文件的一个句柄, 所以必须先释放MapppedByteBuffer之后才能执行文件的删除操作.
    如果使用SUN的JDK, 可以使用:
    public static void clean(ByteBuffer bb) { if (bb == null) return; Cleaner cleaner = ((DirectBuffer) bb).cleaner(); if (cleaner != null) cleaner.clean(); } 如果使用SUN以外的JDK, 例如JRockit, 必须预防该API不存在, 可以借助反射机制来完成兼容代码:


    public
    static void clean(final MappedByteBuffer mbb) { if (mbb == null) { return; } AccessController.doPrivileged(new PrivilegedAction<Object>() { @Override public Object run() { try { Method cleanerMethod = mbb.getClass().getDeclaredMethod("cleaner", new Class[0]); if (cleanerMethod != null) { cleanerMethod.setAccessible(true); Object cleanerObject = cleanerMethod.invoke(mbb, new Object[0]); Method cleanMethod = cleanerObject.getClass().getDeclaredMethod("clean", new Class[0]); if (cleanMethod != null) { cleanMethod.invoke(cleanerObject, new Object[0]); } } } catch (Exception e) { logger.error("关闭MappedByteBuffer句柄错误!", e); } return null; } }); }
    使用AccessController目的是为了启动SecurityManager的时候也有足够的私权去释放内存句柄.
  • 相关阅读:
    HDU2027 统计元音 一点点哈希思想
    湖南工业大学第一届ACM竞赛 数字游戏 字符串处理
    湖南工业大学第一届ACM竞赛 我素故我在 DFS
    HDU3293sort
    HDU2082 找单词 母函数
    HDU1018 Big Number 斯特林公式
    湖南工业大学第一届ACM竞赛 分糖果 位操作
    UVA 357 Let Me Count The Ways
    UVA 147 Dollars
    UVA 348 Optimal Array Multiplication Sequence
  • 原文地址:https://www.cnblogs.com/kelelipeng/p/15753637.html
Copyright © 2011-2022 走看看