首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >MappedByteBuffer不释放内存

MappedByteBuffer不释放内存
EN

Stack Overflow用户
提问于 2016-05-20 20:52:45
回答 1查看 901关注 0票数 0

我在使用NIO MappedByteBuffer函数读取非常大的地震文件时遇到了困难。我的程序读取的格式称为SEGY,由地震数据样本以及关于地震数据的数字ID和XY坐标等项的元数据组成。

这种格式的结构是相当固定的,有一个240字节的头,然后是固定数量的数据样本,组成每个地震道。每个跟踪的样本数可能因文件而异,但通常在1000到2000之间。

示例可以编写为单个字节、16位或32位整数,也可以是IBM或IEEE浮点数。每个跟踪头中的数据也可以采用上述任何格式。为了进一步混淆这个问题,SEGY文件可以是大字节顺序,也可以是小字节顺序。

这些文件的大小可以从3600字节到几个陆地字节不等。

我的应用程序是一个SEGY编辑器和查看器。对于它执行的许多函数,我必须只读取一个或两个变量,比如从每个跟踪头读取一个或两个变量。

目前,我正在将RandomAccessFile读入字节缓冲区,然后从视图缓冲区中提取所需的变量。这是可行的,但对于非常大的文件来说,速度慢得令人痛苦。

我使用映射的字节缓冲区编写了一个新的文件处理程序,该缓冲区将文件分解为5000个跟踪MappedByteBuffers。这很好,而且速度非常快,直到我的系统内存不足,然后缓慢到爬行,我被迫重新启动,以使我的Mac再次可用。

由于某种原因,缓冲区中的内存从未释放,即使在我的程序完成之后也是如此。我要么做个清除要么重新启动。

这是我的密码。如有任何建议,将不胜感激。

代码语言:javascript
复制
package MyFileHandler;

import java.io.*;
import java.nio.*;
import java.nio.channels.FileChannel;
import java.util.ArrayList;

public class MyFileHandler
{

    /*
    A buffered file IO class that keeps NTRACES traces in memory for reading and writing. 
    the buffers start and end at trace boundaries and the buffers are sequential
    i.e  1-20000,20001-40000, etc
    The last, or perhaps only buffer will contain less than NTRACES up to the last trace
    The arrays  BufferOffsets and BufferLengths contain the start and length for all the 
    buffers required to read and write to the file
     */

    private static int NTRACES = 5000;
    private boolean HighByte;
    private long FileSize;
    private int BytesPerTrace;
    private FileChannel FileChnl;
    private MappedByteBuffer Buffer;
    private long BufferOffset;
    private int BufferLength;
    private long[] BufferOffsets;
    private int[] BufferLengths;
    private RandomAccessFile Raf;
    private int BufferIndex;
    private ArrayList Maps;


    public MyFileHandler(RandomAccessFile raf, int bpt)
    {
        try
        {
            HighByte = true;
            //      allocate a filechannel to the file
            FileChnl = raf.getChannel();
            FileSize = FileChnl.size();
            BytesPerTrace = bpt;
            SetUpBuffers();
            BufferIndex = 0;
            GetNewBuffer(0);
        } catch (IOException ioe)
        {
            ioe.printStackTrace();
        }
    }
    private void SetUpBuffers()
    {
    // get number of traces in entire file
        int ntr = (int) ((FileSize - 3600) / BytesPerTrace);

        int nbuffs = ntr / NTRACES;
        //  add one to nbuffs unless filesize is multiple of NTRACES
        if (Math.IEEEremainder(ntr, NTRACES) != 0)
        {
            nbuffs++;
        }
        BufferOffsets = new long[nbuffs];
        BufferLengths = new int[nbuffs];
        // BuffOffset are in bytes, not trace numbers
        //get the offsets and lengths of each buffer
        for (int i = 0; i < nbuffs; i++)
        {
            if (i == 0)
            {
            //  first buffer contains EBCDIC header 3200 bytes and binary header 400 bytes
                BufferOffsets[i] = 0;
                BufferLengths[i] = 3600 + (Math.min(ntr, NTRACES) * BytesPerTrace);
            } else
            {
                BufferOffsets[i] = BufferOffsets[i - 1] + BufferLengths[i - 1];
                BufferLengths[i] = (int) (Math.min(FileSize - BufferOffsets[i], NTRACES * BytesPerTrace));
            }
        }
        GetMaps();

    }
    private void GetMaps()
    {
    //  map the file to list of MappedByteBuffer
        Maps = new ArrayList(BufferOffsets.length);
        try
        {
            for(int i=0;i<BufferOffsets.length;i++)
            {
                MappedByteBuffer map = FileChnl.map(FileChannel.MapMode.READ_WRITE, BufferOffsets[i], BufferLengths[i]);
                SetByteOrder(map);
                Maps.add(map);
            }
        } catch (IOException ioe)
        {
            ioe.printStackTrace();
        }

    }
    private void GetNewBuffer(long offset)
    {
        if (Buffer == null || offset < BufferOffset || offset >= BufferOffset + BufferLength)
        {
            BufferIndex = GetBufferIndex(offset);
            BufferOffset = BufferOffsets[BufferIndex];
            BufferLength = BufferLengths[BufferIndex];
            Buffer = (MappedByteBuffer)Maps.get(BufferIndex);
        }
    }
    private int GetBufferIndex(long offset)
    {
        int indx = 0;
        for (int i = 0; i < BufferOffsets.length; i++)
        {
           if (offset >= BufferOffsets[i] && offset < BufferOffsets[i]+BufferLengths[i])
            {
                indx = i;
                break;
            }
        }
        return indx;
    }

    private void SetByteOrder(MappedByteBuffer ByteBuff)
    {
        if (HighByte)
        {
            ByteBuff.order(ByteOrder.BIG_ENDIAN);
        } else
        {
            ByteBuff.order(ByteOrder.LITTLE_ENDIAN);
        }
    }
    //  public methods to read, (get) or write (put) an array of types, byte, short, int, or float. 
    //  for sake of brevity only showing get and put for ints

    public void Get(int[] buff, long offset)
    {
        GetNewBuffer(offset);
        Buffer.position((int) (offset - BufferOffset));
        Buffer.asIntBuffer().get(buff);
    }


    public void Put(int[] buff, long offset)
    {
        GetNewBuffer(offset);
        Buffer.position((int) (offset - BufferOffset));
        Buffer.asIntBuffer().put(buff);
    }

    public void HighByteOrder(boolean hb)
    {
        //  all byte swapping is done by the buffer class
        //  set all allocated buffers to same byte order
        HighByte = hb;

    }

    public int GetBuffSize()
    {
        return BufferLength;
    }

    public void Close()
    {

        try
        {
            FileChnl.close();
        } catch (Exception e)
        {
            e.printStackTrace();
        }
    }
}
EN

回答 1

Stack Overflow用户

发布于 2016-05-20 22:53:44

您正在通过可能的大量MappedByteBuffers将整个文件映射到内存中,并且当您将它们保存在一个Map中时,它们永远不会被释放。这毫无意义。您还可以用一个MappedByteBuffer映射整个文件,也可以映射克服地址限制所需的最小数量。使用超过你所需的数量是没有好处的。

但我只会映射当前正在查看/编辑的文件段,并在用户移动到另一个段时释放它。

我感到惊讶的是,MappedByteBuffer竟然如此之快。上一次我进行测试时,通过映射字节缓冲区读取的速度仅比RandomAccessFile快20%,而写入速度则完全没有。我希望看到RandomAccessFile代码,因为它看起来可能有一些问题,可以很容易地修复。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/37355672

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档