列表<双>使用 double[] 的 RAM?双>
Java 专家强调避免过早优化并专注于干净的 OO 设计的重要性。我试图在重写使用大量长元素(几百万)的程序的背景下协调这一原则。看起来使用 ArrayList 会消耗原始长整型数组内存的大约 3 倍,并且浪费这么多 RAM 对我来说似乎是一个合理的担忧。
我基于我使用 MemoryTestBench 类此处描述的所做的实验。我的测试和输出如下:
package memory;
import java.util.ArrayList;
import java.util.List;
public class ArrayListExperiment {
public static void main(String[] args) {
ObjectFactory arrayList = new ObjectFactory() {
public Object makeObject() {
List<Long> temp = new ArrayList<Long>(1000);
for (long i=0; i<1000; i++)
temp.add(i);
return temp;
}
};
ObjectFactory primitiveArray = new ObjectFactory() {
public Object makeObject() {
long[] temp = new long[1000];
for (int i=0; i<1000; i++)
temp[i] = i;
return temp;
}
};
MemoryTestBench memoryTester = new MemoryTestBench();
memoryTester.showMemoryUsage(primitiveArray);
memoryTester.showMemoryUsage(arrayList);
}
}
和输出:
memory.ArrayListExperiment$2 produced [J which took 8016 bytes
memory.ArrayListExperiment$1 produced java.util.ArrayList which took 24968 bytes
我的问题是:我怎样才能获得 OO List 的好处,同时仍然保留原始数组的小内存占用?我认为 guava 可能会提供答案,但是浏览一下 API,我并不清楚使用哪个类来代替 ArrayList。
感谢您的任何建议。
Java experts emphasize the importance of avoiding premature optimization, and focusing instead on clean OO design. I am trying to reconcile this principle in the context of rewriting a program that uses a large array of long elements (a few million). It seems that using an ArrayList would consume about 3x the memory of a primitive array of longs, and wasting that much RAM seems like a legitimate concern to me.
I am basing this off an experiment I did using MemoryTestBench class described here. My test and output are as follows:
package memory;
import java.util.ArrayList;
import java.util.List;
public class ArrayListExperiment {
public static void main(String[] args) {
ObjectFactory arrayList = new ObjectFactory() {
public Object makeObject() {
List<Long> temp = new ArrayList<Long>(1000);
for (long i=0; i<1000; i++)
temp.add(i);
return temp;
}
};
ObjectFactory primitiveArray = new ObjectFactory() {
public Object makeObject() {
long[] temp = new long[1000];
for (int i=0; i<1000; i++)
temp[i] = i;
return temp;
}
};
MemoryTestBench memoryTester = new MemoryTestBench();
memoryTester.showMemoryUsage(primitiveArray);
memoryTester.showMemoryUsage(arrayList);
}
}
and output:
memory.ArrayListExperiment$2 produced [J which took 8016 bytes
memory.ArrayListExperiment$1 produced java.util.ArrayList which took 24968 bytes
My question is: How can I reap the benefits of an OO List and still retain the small memory footprint of a primitive array? I think guava might provide the answer, but glancing through the API it's not obvious to me which class to use in place of ArrayList.
Thanks for any suggestions.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
我认为您在 Guava 中寻找的是 双打.asList
I think what you looking for in Guava is Doubles.asList
您可以考虑使用 Trove,它提供对原始集合的支持,例如
TDoubleArrayList
班级:编辑:这个类确实没有实现
List
,但这就是Java避免装箱基元的代价。 Guava 的解决方案是最通用的,而 Trove 最适合更极端的性能要求。You might consider using Trove, which provides support for primitive collections, for example the
TDoubleArrayList
class:Edit: It's true that this class doesn't implement
List
, but that's Java's price of avoiding boxed primitives. Guava's solution is the most versatile, while Trove is best for more extreme performance requirements.我认为您正在寻找 FastUtil
DoubleArrayList
- 它由原始数组支持。如果您的集合确实很大(大于 2^31 个元素),您可能还想查看它们的
BigArrays
I think you are looking for FastUtil's
DoubleArrayList
- it's backed by a primitive array.If your collection is REALLY big (larger than 2^31 elements) you may also want to look at their
BigArrays
编写您自己的使用基元数组的 ArrayList 实现。复制当前的 ArrayList 代码并将内部 Object[] 替换为 double[]。
应该是一个非常直接的复制和替换。
编辑:内存消耗的最大危险将是“增长”。它会暂时占用至少两倍的空间,再加上您种植的额外空间。如果您无法预先调整数组大小来避免这种情况,您可能需要考虑一种稍微不同的实现,该实现使用多个数组,因为它会随着时间的推移而增长。关于插入和索引的更多数学知识,但应该不会太糟糕。
Write your own implementation of ArrayList that uses an array of primitives. Copy the current ArrayList code and replace the internal Object[] with a double[].
Should be a pretty straight foward copy and replace.
EDIT: Biggest danger to memory consumption is going to be the "grow". It will briefly take up at least twice the space, plus the additional room you grow. If you can't pre-size the array to avoid this, you may want to consider a slightly different implementation that uses multiple arrays as it grows over time. A bit more math on inserting and indexing, but shouldn't be tooooo bad.
数组。 asList(T...) 可能就是您正在寻找的。它返回一个由传递给它的数组支持的
List
实例。Arrays.asList(T...) may be what you're looking for. It returns an instance of
List<T>
backed by the array passed to it.这是一个很好的问题——性能与代码整洁度。我认为您有理由不那么关心干净的面向对象设计,而只专注于为处理大量多头数组的特定问题创建一个好的解决方案。如果这样做,将面向性能的代码保留在一个类/包中将最大限度地减少其对整体设计的影响。假设管理大量的多头列表只是更大应用程序的一小部分......
It's a good question - performance vs code-cleanliness. I think you have grounds to be less concerned about clean OO design and simply focus on creating a good solution to the specific problem of working with a large array of longs. If you do so, keeping the performance-oriented code in one class/package will minimise its impact on overall design. Assumedly managing the large list of longs is only a small part of a bigger application...