我正在用java开发游戏,基本上每1/60秒更新一次。在这样的更新期间,创建大量数据,传递然后保持未引用,让我们调用此数据DTO。据我了解,JVM和OS将这些数据存储在程序的堆中。堆积因此构建,直到JAVA GC运行,该分析将所有未引用的数据标记为空闲并准备重用。
现在,我看到它的方式,这是不必要的,偶尔会出现滞后现象。我想解决问题的方法是将一块已分配的内存用作临时堆。此堆用于存储我在更新间隔期间创建和传递的所有临时内容。一旦我到达更新结束,就不需要进行任何分析,但我可以简单地说整个块是免费的,并且这样在更新后重用相同的堆空间更新。有点像尾递归堆栈帧。
另一种解决方案是仅使用可变DTO对象并分配一堆它们并重新使用它们,但我喜欢利用这种优势使事物尽可能不变。
这是为了说明我对代码的意思:
void start(){
Data data = System.allocateDatainMb(500); //allocate 500Mb of virtual memory
MagicHeap() mh = System.createAMagicHeap(data); //make a heap of it
mh.use(); //set all constructors to allocate on this heap
while(true){
update();
mh.clear();
}
}
void update(){
TmpData dto = Gamesystem.createALargePieceOfTemporaryData();
someClass.doUpdateStuff(dto);
}
我不太熟悉Java管理内存的方式,但我希望你明白我的意思。
在某种程度上是否可能?
答案 0 :(得分:0)
我可能会错过一些东西,但我很确定你不能在Java中这样做,因为它会干扰Java自己的内存管理。毕竟,Java旨在保护用户免受低级内存管理例程的影响。
因此,我建议您采用您提到的DTO池方法。改进的一种方法可能是隐藏mutator(例如setter和其他变异方法)并且仅允许工厂方法等访问它们(例如通过使用包私有可见性)。然后让工厂创建/重用看似不可变的实例并管理池。您甚至可以处理临时“溢出”,即当您需要比池实际提供的更多DTO实例时。
但是,如果仔细考虑,如果使用得当,你可能会发现许多你认为生命周期较短的物体。它可能只是某些计算的中间结果(如矢量/矩阵数学),您在下一帧中不需要这些计算,但这些计算通常可以在创建它们之后立即丢弃,在某些情况下也可以避免(例如,如果手动使用基元)或者有多余的中间物品。)
答案 1 :(得分:0)
您要做的是超越JVM。这不是你想要做的。如果你真的需要直接使用内存分配,Java就不是一种合适的语言。
Java的GC经过优化以处理许多短暂的对象,它希望能够在添加后立即从内存中释放大部分内容。不用设置某种缓存系统实际上可以降低性能,因为现在这些对象无法从内存中释放出来,这意味着堆将占用更少的空间,并且(完全)GC暂停将更频繁。这是缓存系统本身产生的任何开销的补充。
这并不意味着你应该忽略Java的内存问题。您应该避免不必要地创建对象,更重要的是,您应该避免长时间保持对象引用,以便您可以允许GC清理它。调整GC以满足您的程序需求并确保您使用现代G1 GC可能也是有益的。
与任何性能调整一样,实际测量更改的性能差异非常重要。对你认为会更快的预感会导致你付出努力并增加复杂性,几乎没有增益,或者更糟糕的是性能下降。确保您有实数来支持任何性能问题。