从文件中读取大量数据。可能有100个不同的数据对象具有必要的标题,但每个数据对象中可以存储超过300,000个值。这些值需要以与读入它们相同的顺序存储。这是数据对象的构造函数:
public Data(String heading, ArrayList<Float> values) {
this.heading = heading;
this.values = values;
}
在RAM中按顺序存储和检索这些值的最快方法是什么?
答案 0 :(得分:1)
虽然在你的评论中你提到&#34; quickness&#34;,但没有指明需要什么操作&#34;快速&#34;,你的主要关注点似乎是堆内存消耗。
让我们假设有100组300,000个数字(你已经使用像#34这样的单词;可能是&#34;和#34;远远超过&#34;但这将作为一个例子)
要存储的30,000,000个数字,加上100个标题和一些用于分组的结构开销。
原始Java float
是32位,即4个字节。所以绝对最低限度,你需要30,000,000 * 4字节== 120MB。
一个基元数组 - float[30000000]
- 只是连接成一个连续的内存块的所有值,所以将消耗120MB的理论最小值 - 加上每个数组一次的几个字节开销我们不会在这里详细介绍。
java Float
包装器对象是12个字节。在数组中存储对象(而不是基元)时,引用本身是4个字节。因此,Float
- Float[30000000]
数组将消耗30,000,000 *(12 + 4)== 480MB。
因此,您可以使用原语而不是包装器将内存使用量削减一半以上。
ArrayList
围绕Object
数组是一个很轻的包装器,因此具有相同的内存成本。在这些列表大小中,每个列表的一次性开销太小而不能与元素相比产生影响。但有一些警告:
ArrayList
只能存储对象,而不能存储基元,因此,如果选择List
,则会遇到Float
的每个元素12个字节的开销。
ArrayList
的容量是动态的,为实现此目的,如果将列表增大到大于其后备数组,它将:
ArrayList.add()
将使用4500万个元素中的一个替换该数组,即使您的List
仅需要30,000,001。< / LI>
ArrayList.trimToSize()
删除不需要的容量,并在填充ArrayList
后重新留下一些记忆。如果我努力使用尽可能少的堆内存,我的目标是将我的数字列表存储为基元数组:
class Data {
String header;
float[] values;
}
......我想把它们放到ArrayList<Data>
。
使用此结构,您可以对任意值进行O(1)访问,并且可以使用Arrays.binarySearch()
(如果值已排序)在组中按值查找。
如果可能的话,我会在读取值之前找出每个组的大小,并将数组初始化为正确的大小。如果可以,请输入您的输入文件格式:
while(line = readLine()) {
if(isHeader(line)) {
ParsedHeader header = new ParsedHeader(line);
currentArray = new float[header.size()];
arrayIndex = 0;
currentGroup = new Group(header.name(), currentArray);
groups.add(currentGroup);
} else if (isValue(line)) {
currentArray[arrayIndex++] = parseValue(line);
}
}
如果您无法更改输入格式,请考虑在文件中进行两次传递 - 一次发现组长度,再次填充数组。
如果您必须一次性使用该文件,并且文件格式无法在群组之前提供群组长度,那么您必须做一些允许& #34;列表&#34;随意成长有几种选择:
将每个群组投放到ArrayList<Float>
- 当群组完成后,将其转换为array[float]
:
float[] array = new float[list.size()];
int i = 0;
for (Float f : list) {
array[i] = f; // auto-unboxes Float to float
}
然而这些都没有考虑到你首先将所有这些数字压入内存的原因,也不考虑这个商店在处理数字时是否满足你的需求。
您应该退后一步,考虑一下您的实际数据处理要求是什么,以及是否啜饮内存是最好的方法。
通过一次只存储一片数据来查看是否可以进行处理,而不是将整个内容存储在内存中。例如,要计算最大/最小/平均值,您不需要每个数字都在内存中 - 您只需要保持运行总计。
或者,考虑使用轻量级数据库库。
答案 1 :(得分:-2)
您可以使用RedBlack BST,这将是一种非常有效的存储/检索数据的方式。这依赖于链接到其他节点的节点,因此只要有足够的内存用于java,输入的大小就没有限制。