Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/390.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java ArrayList<;双倍>;将[]翻一番,有3亿个条目_Java_Memory_Median - Fatal编程技术网

Java ArrayList<;双倍>;将[]翻一番,有3亿个条目

Java ArrayList<;双倍>;将[]翻一番,有3亿个条目,java,memory,median,Java,Memory,Median,我正在使用java程序从数据库中获取一些数据。然后我计算一些数字并开始将它们存储在一个数组中。我用的机器有4吉格的内存。现在,我不知道预先会有多少个数字,所以我使用了一个ArrayList。但我知道大约会有3亿个数字。 因此,由于一个double是8字节,所以粗略估计这个数组将消耗2.4 Gig的内存(可能更多,因为ArrayList的开销)。在此之后,我想计算这个数组的中值,并使用org.apache.commons.math3.stat.description.rank.median库,该库

我正在使用java程序从数据库中获取一些数据。然后我计算一些数字并开始将它们存储在一个数组中。我用的机器有4吉格的内存。现在,我不知道预先会有多少个数字,所以我使用了一个
ArrayList。
但我知道大约会有
3亿个数字。

因此,由于一个double是8字节,所以粗略估计这个数组将消耗2.4 Gig的内存(可能更多,因为ArrayList的开销)。在此之后,我想计算这个数组的中值,并使用
org.apache.commons.math3.stat.description.rank.median
库,该库将
double[]
数组作为输入。因此,我需要将
ArrayList
转换为
double[]

我确实看到了很多问题,它们都提到在整个阵列中循环是没有办法的。现在这很好,但由于它们也在内存中维护这两个对象,因此我的内存需求将达到4.8Gig。现在我们遇到了一个问题,因为总RAM为我们提供了4 Gig


首先,我是否怀疑该程序在某个时候会给我一个正确的内存错误(它当前正在运行)?如果是这样,我如何计算中位数而不必分配双倍的内存?我希望避免对数组进行排序,因为计算中位数是O(n)。

您的问题甚至比您意识到的更糟,因为
ArrayList
的效率远远低于每个条目8个字节。每个条目实际上都是一个对象,
ArrayList
保存一个引用数组。一个
Double
对象大约有12个字节(4个字节用于某种类型的标识符,8个字节用于
Double
本身),对它的引用再加上4个字节,使每个条目的总字节数达到16个,甚至不包括内存管理等开销

如果约束范围再宽一点,您可以实现自己的
DoubleArray
,它由
double[]
支持,但知道如何调整自身大小。但是,调整大小意味着您必须同时在内存中保留新数组和旧数组的副本,这也超出了内存限制

尽管如此,仍有一些选择:

  • 循环输入两次;一次清点条目,一次将条目读入合适大小的
    double[]
    。当然,这取决于您的输入的性质,这是否可能

  • 假设最大输入大小(可能是用户可配置的),并预先分配一个固定大小的
    double[]
    。只使用已填充的部分

  • 使用
    float
    而不是
    double
    将内存需求减半,但会牺牲一些精度

  • 重新考虑您的算法,避免将所有内容同时保存在内存中


中值是排序列表中间的值。因此,您不必使用第二个数组,只需执行以下操作:

Collections.sort(myArray);
final double median = myArray.get(myArray.size() / 2);

由于数据是从数据库中获取的,所以您可以告诉数据库给您中位数,而不是用Java,这将节省传输数据的所有时间(和内存)。

有许多开源库为原语创建动态数组。其中一项:

我同意,使用Trove4j
t浮动数组列表
class(请参阅)存储双精度或
t浮动数组列表
。结合前面的答案,我们得到:

// guess initialcapacity to remove requirement for resizing
TDoubleArrayList data = new TDoubleArrayList(initialcapacity);
// fill data
data.sort();
double median = data.get(data.size()/2);

写一段代码来说明你在做什么。如果数据在数据库中,为什么不使用数据库来执行计算?你说的是从查询中检索3亿行?你在用什么数据库?谢谢你的回答。。因此,double[]数组需要不超过8*大小的数组内存吗?或者这也会带来一些开销吗?double[]没有任何每元素开销,但是Collections.sort()可能会决定使用mergesort,这将需要加倍内存并引发错误(对吗?)或者在给定数组大小的情况下,它会知道使用快速排序吗?我不能直接使用sql,因为我对需要多个循环的数据进行处理。Collections.sort()也不能让您走得更远,因为它会带来双重装箱开销。如果您决定选择O(n log n),请过度分配,然后使用Arrays.sort()的3个参数变量: