2

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

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

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

它们作为它们的确切数据类型存储在数组列表中。我查看了 MemoryMappedFiles,尽管我不确定它们是否会提供我需要的功能,文本文件是用制表符分隔的,有 40 列我需要在 JTable 中显示,同样我认为如果我不能使用内存映射文件需要显示到 JTable 但也许我错了。

任何建议,将不胜感激。

数据存储如下,我需要将所有数据都存储在内存中的原因是因为在任何时候出于计算目的我都需要访问文件中的任何行。

这是在我的 JTable 表模型中,请注意传递给表模型的行数据在确保内存中没有重复副本之后被清空

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);
       }
   }
}
4

3 回答 3

2

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

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

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

所以不要加载它们。逐行或逐段处理它们,无论在您的文件中意味着什么,或使用数据库。

文本文件用制表符分隔,有 40 列我需要在 JTable 中显示

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

于 2013-08-20T09:58:05.340 回答
2

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

还逐行从文件中读取数据。读取下一行后,将此数据放入您的结构中。

例如,如果您需要两个文件 id 和 name,您可以创建如下内容:

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 条记录并提供页面导航时。

于 2013-08-20T07:32:02.160 回答
1

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

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

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

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

同一点与您提到的其他类型有关。唯一的内存占用保存会出现在数字类型中,例如int.

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

说到这一点,二进制序列化有很大的意义,因为它可以为您节省硬盘空间。

于 2013-08-20T07:12:38.313 回答