作为开场白-我对这个问题的设计没有任何影响,我也不能给出更多关于技术背景的细节。
假设我有许多相同类型的组件定期获得布尔事件-我需要保存这些布尔事件的简短历史记录。
我的一个同事使用Map<Component, CircularFifoQueue<Boolean>>类型编写了一个相当简单的实现,CircularFifoQueue是来自Apache Commons的数据结构。代码可以工作,但是考虑到泛型在Java中的工作方式和所使用的维度,这是非常低效的,因为它存储了对两个单例布尔对象之一的引用,而不是只存储一个位。
一般来说,大约有100K个组件,历史记录应该包含5-10个最近的布尔值(可能会发生变化,但可能不会大于10)。这意味着目前仅为这些历史地图就分配了大约1.5 of的RAM。此外,这些更改经常发生,因此如果可能的话,提高CPU效率也不会有什么坏处。
一个明显的变化是将历史记录移到Component类中,以消除由HashMap引起的开销。
更复杂的问题是如何有效地存储最后几个布尔值。一种可能的方法是使用BitSets,但是由于那些使用long[]作为底层数据结构的人,我怀疑这是否是存储本质上是5位的内容的最有效的方式。
另一种选择是直接使用整数并将值移位,作为删除旧条目的一种方式。所以基本上
int history = 0;
public void set(int length, boolean active){
if(active) {
history |= 1 << length;
} else {
history &= ~(1 << length);
}
// shift one to the right to remove oldest entry
history = history >> 1;
}就在我的脑海里。这段代码是未经测试的。我不知道它的效率如何,也不知道它是否有效,但这就是我的想法。
但与使用5位内存存储5位数据的最佳情况相比,这仍然会导致相当大的开销。
如果将不同组件的历史存储在一个连续的数组中,可以实现一些额外的节省,但是我不确定如何处理任何一个巨大的连续的BitSet。或者可替换地,一个较大的byte[],其中每个字节表示如上所述的一个布尔历史。
这是一个奇怪的具体问题,我真的很高兴有任何建议。
发布于 2019-08-16 02:41:54
抛开我相信你会克服的位操作,请想一想,效率如何才够有效。
的每个实例
class Foo {}分配16 bytes。所以如果你要介绍
class ComponentHistory {
private final int bits;
}这是20个字节。
如果将int替换为byte,仍然是20个字节:byte类型至少是padded to 4 bytes by JVM。
如果您在某个地方定义了一个全局位数组并从ComponentHistory引用它,则引用本身位于least 4 bytes。
基本上,你赢不了:)
但考虑到这一点:如果您采用您已经概述的最简单的方法,即生成简单的可读代码,那么您的100K组件历史将占用2MB的RAM -与您当前1.5 go的级别相比节省了大量的内存。具体地说,您节省了1498MB。
假设您确实发明了一种繁琐但有效的方法,即每个历史记录只存储5位。然后,您需要500Kb = 60KB来存储所有历史记录。使用1.5 of的基线,您现在节省了1499.94MB。节省了0.1%的。这有什么关系吗?通常情况下,我不希望在这里过度优化,同时牺牲简单性。
https://stackoverflow.com/questions/57513825
复制相似问题