Java性能/内存消耗:类与数组



顺便说一下:最近,我在一个Java项目中遇到了这样一种情况:我可以将一些数据存储在二维数组中,也可以为它创建一个专用的类,然后将其实例放入一维数组中。所以我想知道是否有一些规范的设计建议在这个主题的性能方面(运行时,内存消耗)?

不考虑设计模式(极其简化的情况),假设我可以像

这样存储数据
class MyContainer {
  public double a;
  public double b;
  ...
}

MyContainer[] myArray = new MyContainer[10000];
for(int i = myArray.length; (--i) >= 0;) {
  myArray[i] = new MyContainer();
}
...

double[][] myData = new double[10000][2];  
...

我莫名其妙地认为基于数组的方法应该更紧凑(内存)和更快(访问)。然后,也许不是,数组也是对象,数组访问需要检查索引,而对象成员访问不需要。对象数组的分配可能会花费更长的时间,因为我需要迭代地创建实例,并且由于额外的类,我的代码将更大。

因此,我想知道在访问速度和内存消耗方面,通用jvm的设计是否为一种方法提供了优于另一种方法的优势?许多谢谢。

也许不是,数组也是对象

这是正确的。所以我认为这种方法不会给你带来任何好处。

如果你想沿着这条路走下去,你可以把它平铺成一个一维数组(然后你的每个"对象"占用两个槽)。这将使您可以立即访问所有对象中的所有字段,而不必遵循指针,并且整个事情只是一个大的内存分配:由于您的组件类型是原始的,因此就内存分配而言,只有一个对象(容器数组本身)。

这是人们希望在Java中拥有结构和值类型的动机之一,类似的考虑推动了专门的高性能数据结构库的开发(摆脱了不必要的对象包装器)。

我不会担心这个问题,除非你真的有一个庞大的数据结构。只有这样,面向对象方式的开销才会起作用。

我认为基于数组的方法应该更紧凑(内存)和更快(访问)

它不会。您可以通过使用Java Management接口轻松地确认这一点:

com.sun.management.ThreadMXBean b = (com.sun.management.ThreadMXBean) ManagementFactory.getThreadMXBean();
long selfId = Thread.currentThread().getId();
long memoryBefore = b.getThreadAllocatedBytes(selfId);
// <-- Put measured code here
long memoryAfter = b.getThreadAllocatedBytes(selfId);
System.out.println(memoryAfter - memoryBefore);

在测量代码下放置new double[0]new Object(),您将看到这些分配将需要完全相同的内存量。

可能是JVM/JIT以一种特殊的方式处理数组,从而可以以某种方式更快地访问它们。

如果for循环,JIT对数组进行一些向量化操作。但它更多的是算术运算的速度,而不是访问的速度。除此之外,我想不出任何

我在这种情况下看到的规范建议是,过早优化是万恶之源。遵循这一点意味着你应该坚持最容易编写/维护/通过代码质量制度的代码,然后如果你有一个可衡量的性能问题,看看优化。

在您的示例中,内存消耗是相似的,因为在对象情况下,您有10,000个引用加上每个引用的两个双精度,而在2D数组情况下,您有10,000个引用(第一个维度)到每个包含两个双精度的小数组。所以两者都是一个基引用+ 10,000个引用+ 20,000个双精度引用。

更有效的表示应该是两个数组,其中有两个基引用和20,000个双精度对象。

double[] a = new double[10000];
double[] b = new double[10000];

最新更新