文件加载到比磁盘更大的内存

时间:2013-08-20 06:54:58

标签: java memory jtable out-of-memory memory-mapped-files

我正在将java中的文本文件加载到内存中。文本文件的大小为100 MB,包含数千行String,Integer或Double类型。

如果我使用64位JDK进行编译,一旦加载到内存中虽然它占用整个1 GB或更多。

这是一个问题,因为我需要加载更大的文件。

它们作为精确数据类型存储在arraylist中。我查看了MemoryMappedFiles,虽然我不确定它们是否会提供我需要的功能,但是我需要在JTable中显示40个列的文本文件,我再也不认为我可以使用内存映射文件需要显示成JTable,但也许我错了。

任何建议都将不胜感激。

数据存储如下,我需要将其全部存储在内存中的原因是因为在任何时候我都需要访问文件中的任何行。

这是我在JTable的表模型中,注意传递给tablemodel的rowdata被删除后确保内存中没有重复的副​​本

private Object[][] data;

public TableModel(ArrayList<String> headers, RowData[] importedData)
{                
   columnNames = new String[headers.size()];
   data = new Object[importedData.length][headers.size()];

   for (int i = 0; i < headers.size(); i++) // extract the column names
    {                                        // for the table
        this.columnNames[i] = headers.get(i);
    }

   for (int i = 0; i < importedData.length; i++)  // extracting the data
   {                                              // for the table
       for (int j = 0; j < headers.size(); j++)
       {
            this.data[i][j] = importedData[i].myList.get(j);
       }
   }
}

3 个答案:

答案 0 :(得分:2)

我认为你在你的记忆结构中使用了很多小物件。可能会给你带来开销。根据我的经验,减少内存消耗的最佳方法是使用普通数组。您可以将此数组包装到其他结构中。当我使用这种方法时,它为我节省了70%的记忆。它不是干净的代码,但如果你需要保存内存 - 它会起作用。

还逐行从文件中读取数据。在下一行被引入后,将这些数据放入您的结构中。

例如,如果您需要两个文件ID和名称,您可以创建类似:

public class DataStructure {

    private final static int SIZE_STEP = 32;

    private int size = 0;
    private int[] ids = new int[SIZE_STEP];
    private String[] names = new String[SIZE_STEP];

    public void add(int id, String name) {
        if(size >= ids.length) {
            ids = Arrays.copyOf(ids, ids.length + SIZE_STEP);
            names = Arrays.copyOf(names, names.length + SIZE_STEP);
        }
        ids[size] = id;
        names[size] = name;
        size++;
    }

    public int getId(int index) {
        return ids[index];
    }

    public String getName(int index) {
        return names[index];
    }
}

其他方法可以是分页。例如,当您仅显示20条记录并提供页面导航时。

答案 1 :(得分:1)

我已经在.NET平台上解决了这个问题,原因可能是相同的。

如果您在硬盘驱动器上的文件中输入字符串“hello”,则并不意味着new String("hello")在内存中也占用2x5bytes。

在.NET中,字符串的新初始化需要大约40字节,因为在内存中有关于对象定义本身的一些事情。

我找到了很好的java文章 - http://www.javamex.com/tutorials/memory/string_memory_usage.shtml。它显示确切的数字

同样的观点与您提到的其他类型有关。在int等数字类型中,唯一的记忆占用保存会浮现在脑海中。

文件中的数字124567只是字符串,它采用2xsize-of-string-representation,例如。在UTF-8的情况下为2x7bytes。另一方面,内存中的int实例占用4个字节。

谈到这一点,binary serialization有很大的意义,因为它可以为您节省硬盘空间。

答案 2 :(得分:1)

  

文本文件的大小为100 MB,包含数千行String,Integer或Double类型。

不,不。它包含数千行文本,以文本十进制格式表示字符串,整数或双精度。任何类型的文本文件中都没有对象。因此,当您将其加载到内存中并转换为对象格式时,内存使用量将会发生变化。

  

这是一个问题,因为我需要加载更大的文件。

所以不要加载它们。

。逐行处理,或逐段处理,无论文件中的含义如何,都可以处理。

  

文本文件是用40个列删除的标签,我需要在JTable中显示

您不需要在JTable.的40列中显示数百兆字节的数据,这意味着需要数千行。这只是一个用户界面的噩梦。不可用。重新设计UI以使用过滤器,重新设计数据以使用数据库,重新设计应用程序以加载过滤后的数据并显示它。