Java Performance/Memory 消耗:Class 对比数组
Java Performance/Memory Consumption: Class vs. Array
出于兴趣:最近,我在我的一个 Java 项目中遇到了一种情况,我可以将一些数据存储在二维数组中或为其创建一个专用的 class我将放入一维数组的实例。所以我想知道在性能(运行时、内存消耗)方面是否存在一些关于这个主题的规范设计建议?
不考虑设计模式(极其简化的情况),假设我可以像这样存储数据
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];
...
我不知何故认为 基于数组的方法应该更紧凑(内存)和更快(访问)。再一次,也许不是,数组也是对象,数组访问需要检查索引,而对象成员访问则不需要。(?)对象数组的分配可能(?)需要更长的时间,因为我需要迭代创建由于额外的 class.
,实例和我的代码会更大
因此,我想知道在访问速度和内存消耗方面,常见 JVM 的设计是否为一种方法提供了优于另一种方法的优势?
非常感谢。
Then again, maybe it is not, arrays are objects too
没错。所以我认为这种方法不会给你带来任何好处。
如果你想沿着这条路走下去,你可以把它展平成一个一维数组(每个 "objects" 然后占用两个槽)。这将使您可以立即访问所有对象中的所有字段,而不必遵循指针,并且整个事情只是一个大内存分配:因为您的组件类型是原始的,所以就内存分配而言只有一个对象(容器数组本身)。
这是人们的动机之一 wanting to have structs and value types in Java,类似的考虑推动了专门的高性能数据结构库的开发(摆脱了不必要的对象包装器)。
不过,在您真正拥有庞大的数据结构之前,我不会担心它。只有这样,面向对象方式的开销才会重要。
I somehow think that the array-based approach should be more compact (memory) and faster (access)
不会。您可以使用 Java 管理界面轻松确认这一点:
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()
,您会发现这些分配将需要完全相同的内存量。
It might be that the JVM/JIT treats arrays in a special way which could make them faster to access in one way or another.
JIT 做一些 vectorization of an array operations if for-loops。但它更多的是关于算术运算的速度而不是访问速度。除此之外,想不出来了。
我在这种情况下看到的规范建议是过早优化是万恶之源。遵循这意味着您应该坚持使用最容易编写/维护/通过代码质量制度的代码,然后在遇到可衡量的性能问题时查看优化。
在你的例子中,内存消耗是相似的,因为在对象的情况下你有 10,000 个引用加上每个引用两个双精度数,而在二维数组的情况下你有 10,000 个引用(第一维)到每个包含两个双精度数的小数组.所以两者都是一个基本参考加上 10,000 个参考再加上 20,000 个双打。
更有效的表示是两个数组,其中有两个基本引用加上 20,000 个双精度值。
double[] a = new double[10000];
double[] b = new double[10000];
出于兴趣:最近,我在我的一个 Java 项目中遇到了一种情况,我可以将一些数据存储在二维数组中或为其创建一个专用的 class我将放入一维数组的实例。所以我想知道在性能(运行时、内存消耗)方面是否存在一些关于这个主题的规范设计建议?
不考虑设计模式(极其简化的情况),假设我可以像这样存储数据
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];
...
我不知何故认为 基于数组的方法应该更紧凑(内存)和更快(访问)。再一次,也许不是,数组也是对象,数组访问需要检查索引,而对象成员访问则不需要。(?)对象数组的分配可能(?)需要更长的时间,因为我需要迭代创建由于额外的 class.
,实例和我的代码会更大因此,我想知道在访问速度和内存消耗方面,常见 JVM 的设计是否为一种方法提供了优于另一种方法的优势?
非常感谢。
Then again, maybe it is not, arrays are objects too
没错。所以我认为这种方法不会给你带来任何好处。
如果你想沿着这条路走下去,你可以把它展平成一个一维数组(每个 "objects" 然后占用两个槽)。这将使您可以立即访问所有对象中的所有字段,而不必遵循指针,并且整个事情只是一个大内存分配:因为您的组件类型是原始的,所以就内存分配而言只有一个对象(容器数组本身)。
这是人们的动机之一 wanting to have structs and value types in Java,类似的考虑推动了专门的高性能数据结构库的开发(摆脱了不必要的对象包装器)。
不过,在您真正拥有庞大的数据结构之前,我不会担心它。只有这样,面向对象方式的开销才会重要。
I somehow think that the array-based approach should be more compact (memory) and faster (access)
不会。您可以使用 Java 管理界面轻松确认这一点:
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()
,您会发现这些分配将需要完全相同的内存量。
It might be that the JVM/JIT treats arrays in a special way which could make them faster to access in one way or another.
JIT 做一些 vectorization of an array operations if for-loops。但它更多的是关于算术运算的速度而不是访问速度。除此之外,想不出来了。
我在这种情况下看到的规范建议是过早优化是万恶之源。遵循这意味着您应该坚持使用最容易编写/维护/通过代码质量制度的代码,然后在遇到可衡量的性能问题时查看优化。
在你的例子中,内存消耗是相似的,因为在对象的情况下你有 10,000 个引用加上每个引用两个双精度数,而在二维数组的情况下你有 10,000 个引用(第一维)到每个包含两个双精度数的小数组.所以两者都是一个基本参考加上 10,000 个参考再加上 20,000 个双打。
更有效的表示是两个数组,其中有两个基本引用加上 20,000 个双精度值。
double[] a = new double[10000];
double[] b = new double[10000];