避免Java中的缓存未命中
目前,我正在改变想法,开发更方便缓存的应用程序。避免Java中的缓存未命中,java,caching,garbage-collection,Java,Caching,Garbage Collection,目前,我正在改变想法,开发更方便缓存的应用程序。 在C++中,我使用栈分配的方式,也可以用一个数组(数据驱动编程)来保存数据。 但我也是Java开发人员,有一个问题: 我听说Java是“缓存未命中生成器”。 所有东西都在堆中,在分配或垃圾收集器工作后分散在整个RAM中。我认为C#也存在同样的问题。 以数据驱动的方式编写Java有意义吗? 是否有任何方法可以优化Java代码,或者我们被Java自动优化和缓存未命中所困扰?您也可以在Java中提高缓存性能,但这涉及到它。基元类型的数组是连续的内存块,
在C++中,我使用栈分配的方式,也可以用一个数组(数据驱动编程)来保存数据。 但我也是Java开发人员,有一个问题:
我听说Java是“缓存未命中生成器”。
所有东西都在堆中,在分配或垃圾收集器工作后分散在整个RAM中。我认为C#也存在同样的问题。
以数据驱动的方式编写Java有意义吗?
是否有任何方法可以优化Java代码,或者我们被Java自动优化和缓存未命中所困扰?您也可以在Java中提高缓存性能,但这涉及到它。基元类型的数组是连续的内存块,因此,只要您可以根据自己喜欢的内容重写代码。正如Stepanov所说,您可以用任何语言编写FORTRAN。我在过去看到过这种做法,但这并不好
另一方面,C#在这方面是一种更友好的语言
struct
类型具有连续的成员,因此您可以在C#中构建更高级别的缓存友好抽象,另外,值类型的List
在单个连续内存块中分配T
。我的第一个建议是不要花太多时间担心它,除非您有未达到的特定性能目标。此外,在编写高效的Java代码时,还有许多其他途径需要探索
。。。但是,如果你真的想完成这条路径,你可以考虑“轻量级对象”模式(或轻量级):
原语的数组和类可能会占用连续的存储空间,因此您可以将这些对象用于底层存储,并使用位于顶部的适配器类返回数据的OO表示
您必须小心不要分配给许多适配器。如果一个适配器对象将引用传递到底层数据数组中,光标类型模式可能会很有用
<>在C++中,我使用栈分配的方式,也可以用一个数组(数据驱动编程)等…
在Java中,它将使用Escape分析自动在堆栈上放置短期的OBEJCT。我不会担心这一点,除非你在剖析器中看到这是一个问题。即使如此,分析器也可能阻止了逃逸分析的工作,这在实际程序中不是问题
我听说Java是“缓存未命中生成器”
<> > java比C++或C代码更具参考性,它是用嵌入对象内部的结构或对象编写的。这会产生多大的差异取决于应用程序对微调的敏感程度
所有东西都在堆中,在分配或垃圾收集器工作后分散在整个RAM中。我认为C#也存在同样的问题
Java(和C#)也不是一个随机内存安排程序。从理论上讲,物体可能在任何地方,但在实践中,它们通常不是。考虑一下你有没有;p>
class A { }
class B {
A a = new A();
}
如果创建B
,a
可以在任何地方,但通常不是。当Java在Eden空间中分配内存时,它在内存中通常是连续的。这是分配内存最简单、最有效的方法。这意味着99.9%的时间,A
将紧跟在B
之后,可能在同一缓存线上。事实上,对于某些用例,“虚假共享”在Java中是一个真正的问题。i、 e.当您想要删除不在同一缓存线上的两个对象时
GC上会发生什么
在OpenJDK/Oracle JVM中,对象的复制顺序与发现顺序相反。i、 e.A
在大多数情况下会出现在B
之前
以数据驱动的方式编写Java有意义吗
这种情况就是这样,在<1%的情况下,这会产生很大的影响。然而,对于大多数代码,如果不是大多数应用程序,您将有很多更大的问题需要担心
有没有办法优化Java代码,或者我们被Java自动优化和缓存未命中所困扰
您可以使用Unsafe
来控制您选择的内存结构。我们(编年史软件)的库允许您这样做,但即使我们希望您使用我们的服务,在99%的情况下,也没有理由担心这种微调。只有在极端情况下,它才会产生真正的影响
我不想修改垃圾收集器。但我知道它会复制周围的所有内容,所以会弄乱一点结构。我希望尽可能避免这种情况
这就是GC所做的。它将相关对象打包在一起,这不仅是为了提高效率,而且因为以找到对象的方式复制对象是最简单的实现。如果你想随机安排数据,你就必须有意识地这样做,这将是更多的工作。e、 g.如果你想避免“错误共享”,这是非常重要的。你可以优化缓存未命中,但这涉及到处理人为复杂的类层次结构、大量数组,或者走
sun.misc.Unsafe
之路,这会增加自身的开销
Java对内存布局几乎没有保证。你有两个强有力的保证:
- 超类的字段一起保存在内存中(可以避免错误共享,而无需诉诸
)sun.misc.confered
- 数组在内存中是连续的
ArrayList
代替LinkedList
,HashMap
代替TreeMap
如果您需要更多的控制,请使用开放寻址映射,特别是在处理基本类型(有一个fe)时