在设计java类时,对于实现CPU缓存友好性有哪些建议?
到目前为止我学到的是应该尽可能多地使用 POD(即 int 而不是整数)。这样,在分配包含对象时,数据将被连续分配。例如。
class Local
{
private int data0;
private int data1;
// ...
};
比缓存更友好
class NoSoLocal
{
private Integer data0;
private Integer data1;
//...
};
后者将需要对可以位于内存中任意位置的 Integer 对象进行两次单独的分配,尤其是。 GC 运行后。 OTOH 在数据可以重用的情况下,第一种方法可能会导致数据重复。
有没有办法让它们在内存中彼此靠近,以便父对象及其包含元素将立即位于 CPU 缓存中,而不是任意分布在整个内存上,并且 GC 会将它们保持在一起?
您不能强制 JVM 将相关对象放置得彼此靠近(尽管 JVM 会尝试自动执行此操作)。但有一些技巧可以使 Java 程序对缓存更加友好。
让我向您展示一些现实项目中的例子。
BEWARE!这不是推荐的 Java 编码方式!
除非您完全确定为什么要这样做,否则不要采用以下技术。
继承优于组合。你肯定听说过相反的原则“优先考虑组合而不是继承” https://stackoverflow.com/questions/49002/prefer-composition-over-inheritance。但对于构图,你有一个额外的参考可以遵循。这对于缓存局部性不利,并且还需要更多内存。经典的例子是继承优于组合是扩展实用程序的 JDK 8 加法器和累加器类Striped64
班级。
-
将结构数组转换为数组结构。这再次有助于节省内存并加速单个字段的批量操作,例如关键查找:
class Entry {
long key;
Object value;
}
Entry[] entries;
将被替换为
long[] keys;
Object[] values;
-
通过内联扁平化数据结构。我最喜欢的例子是内联 160 位 SHA1 哈希,表示为byte[]
。之前的代码:
class Blob {
long offset;
int length;
byte[] sha1_hash;
}
之后的代码:
class Blob {
long offset;
int length;
int hash0, hash1, hash2, hash3, hash4;
}
Replace String
with char[]
。你知道,String
在Java中包含char[]
引擎盖下的对象。为什么要为额外的参考而付出性能损失?
避免链接列表。链表对缓存非常不友好。硬件最适合线性结构。LinkedList
经常可以替换为ArrayList
。经典之作HashMap
可以替换为打开地址哈希表 http://en.wikipedia.org/wiki/Open_addressing.
使用原始集合。 Trove http://trove.starlight-systems.com/是一个高性能库,包含原始类型的专用列表、映射、集合等。
在数组或字节缓冲区之上构建您自己的数据布局。字节数组是完美的线性结构。为了获得最佳的缓存位置,您可以手动将对象数据打包到单个字节数组中。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)