我正在使用box2d在Java中创建一个物理游戏。
我正在编写一个AI类,并希望在考虑内存对齐的情况下确保尽可能高效地存储我的数据。
最小的增加可能会产生巨大的变化,因为我实际上正在“尽可能多地运行AI对象”,直到系统变慢为止。该程序已经在碰撞检测上使用了大量内存,因为我想再次能够支持尽可能多的代理商。
到目前为止,我所了解的是,最小的Java类型是8bytes,并且对象被填充为8的倍数。我已经将我的AI控件构造为布尔数组,表示运动:x +/- 1,y
+/- 1和顺时针方向/ CCW旋转用于某些灯具。
由于Java没有为布尔值设置空值,因此我将控件嵌套在具有bool值on_off和pos_neg的命令对象中。通过移动和旋转,我每个“默认”操作(例如向右移动)处理大约7个命令对象。所以我为每个动作创建Command数组。
我的问题是:我能有效地做到这一点吗?
我还没有完成设计,所以我不确定每个数组的大小。但是,考虑到内存对齐的要求,我猜我至少 会有一些
填充,这最终会浪费内存,我正在考虑做一些事情,例如削减对象大小以适合填充限制,然后将剩余数据从多个对象变成“溢出”对象…之类的东西。
这样会加快速度吗?为什么或者为什么不?
我还考虑使用位集,尽管我认为我的命令对象可能已经达到了类似的结果,并且有人告诉我位移很慢。
public class Command {
boolean on_off = false;
boolean pos_neg = false;
}
public class DefaultMoves {
//Note: these arrays are 2d in the event multiples are necessary
//to complete a single action, I may change this later.
Command[][] mvRight =
{
{ new Command(false, false), //
new Command(false, false), //
new Command(false, false), //
new Command(false, false), //
new Command(false, false), //
new Command(true, true), //moveX
new Command(false, false) //
},
};
Command[][] mvLeft =
{
{ new Command(false, false), //
new Command(false, false), //
new Command(false, false), //
new Command(false, false), //
new Command(false, false), //
new Command(true, false), //moveX
new Command(false, false) //
},
};
}
这只是一个评论,但是有点冗长,我不想把它写成3条评论。
由于这是另一个后续问题,因此我将从“停止担心填充”开始。担心您如何存储数据。
而且,如果您担心自己的东西要占用多少空间,请分配7个对象而不是7个单个对象的数组。我确定Java每次分配都有开销。在典型的C或C
++实现中,每个带有new
或malloc
超过16-32个字节的分配都超出分配的实际数据的大小,并且大小四舍五入为16或32个字节。在Java中,这里有一个建议,即对象的内存开销为8字节-
这可能不适用于所有Java VM和实现。
此外,所有时空优化都是时空之间的折衷(至少几乎总是如此),因此以更紧凑的形式存储数据将节省时间以节省空间。例如,我可以认为在较大的整数结构中具有on_off
和pos_neg
为两个位。因此,您的7个命令将存储在一个整数中。但是,现在您必须进行移位和屏蔽才能获取正确的数据。同样,如果要存储某些内容,请转移和操作。(由于我不太了解Java,因此我将其编写为C)。
/* This is big enough for 16 pairs of on_off and pos_neg */
/* In a pair of bits, bit 0 = on_off, bit 1 = pos_neg */
uint32_t cmdData;
/* Get values of on_off and pos_neg for element number n */
void getData(int n, bool& on_off, bool& pos_neg)
{
uint32_t shifted = cmdData >> (2 * n);
on_off = (shifted & 1) != 0;
pos_neg = (shifted & 2) != 0;
}
/* Store values for element n */
void setData(int n, bool on_off, bool pos_neg)
{
uint32_t bits = (int)on_off + (2 * (int)pos_neg);
uint32_t mask = 3 << (n * 2);
cmdData &= ~mask; /* Clear bits */
cmdData |= bits << (n * 2);
}
如您所见,这可以更有效地存储数据,因为我们可以{on_off, pos_neg}
在4个字节中存储16对数据,而不是每个(可能)占用一个字节。但是,要深入了解每种方法,您每次都必须执行一些额外的操作(并且代码变得更加混乱)。是否“值得拥有”在很大程度上取决于情况,访问这些对象的频率与系统的内存量有多低(假设这些对象的内存使用量是造成问题的原因-
如果您有100个命令结构,并且使用该命令的40000000个对象,那么这些命令就不会成为问题。
我存储方向/移动命令的方式可能是两个整数值(如果空间狭窄,则在int8_t
[ byte
java中]),按住a
+1
可以例如向右或向下-1
移动,向左或向上移动。这不是最紧凑的形式,但是它使您可以轻松访问和轻松计算新职位。
然后可以使用该对描述所有可能的方向:
struct direction
{
int x, y;
};
direction directions[] =
{
{ 0, 0 }, // Don't move.
{ 0, 1 }, // Right.
{ 0, -1 }, // Left.
{ 1, 0 }, // Down.
{ -1, 0 }, // Up.
};
如果您也想对角移动,则必须添加另外四对,并结合{ 1, 1 }, {-1, 1}
,等等。
可以将其作为一对xDir, yDir
值应用于可以移动的对象。
但关键是您首先要对更重要的内容(空间或计算)有一个很好的了解。从中,找出哪些对象占用了大部分空间(计数最高的对象)。摆弄一个或几十个物体的大小不会有太大的不同,有些东西你有数百万个意志。如果空间不是问题(为了公平起见,在具有千兆字节RAM的系统中,编写代码有效地使用足够大量的数据确实很困难-
如果您使用内存,通常是CPU耗尽了内存才耗尽速度对每一帧的每个对象做一些事情。
手提箱类比:
想象一下,您有一个手提箱,可以在其宽度上正好容纳4个小盒子(在长度上可以容纳任何数字-
这是一个奇怪的手提箱!),而您有一个大盒子,它们是1个,2个,3个或4个小盒子。盒子是用“魔术贴”制成的,所以它们可以粘在一起,可以随意拆分,但是您必须跟踪它们属于哪个,每次“拆分”或“放回”这些单元时,额外的时间。
如果您想变得懒惰并且简单易用,只需将三盒装的行李箱放进手提箱,每个箱子旁边都留一个空白。
1 2 3 4
a a a x
b b b x
c c c x
d d d x
等等。
如果要紧紧包装,请先取一个3个单位的盒子,然后再切下一个,再将其粘贴在第一个旁边,然后将剩余的两个单位放在下一个空间,然后切成两个单位从下一个开始,并将其粘贴到数据包2旁边,依此类推。
1 2 3 4
a a a b
b b c c
c d d d
现在,您已经使用了25%的空间来存储它们,但是您花了一些时间将它们拆分,并且当您以后需要使用数据时,您不得不花时间再次将它们分成三个单元。
现在,想像一下您拿钱将东西放进手提箱,然后按所放物品的钱领取,您选择哪种方法?
然后,您不必为每件商品付费,而必须为行李箱空间付费(因为您是公司的所有者)。现在,您想尽可能地挤入空间。但这需要额外的时间,对吗?如果手提箱很贵,那也许值得。如果不是那么贵,您可能更希望节省时间而不是空间。这是一个妥协。
[我们可以以更实际的单位8、32或64进行相同的操作,但是我认为那只会使阅读变得更困难,并且打字也变得更加困难]
此为在原版2048的基础上,添加了电脑AI解题,并稍微修改了UI添加按钮来触发AI。 AI的核心在/js/myAI.js里,相关函数在window.myPlugin里 核心算法是用dfs搜3步后使代价函数window.myPlugin.evalCost期望值最小的走法, 代价函数的设计目的是让块尽量按由大到小顺序堆叠在右上角,并合并。 实验效果是基本能保证到2048,偶尔到4096甚至8192(概率较小)。
问题内容: 我使用pygame在python中做了一个非常简单的游戏。分数基于玩家所达到的等级。我将级别作为一个名为的变量。我想在游戏开始或结束时显示最高级别。 我会更乐于显示一个以上的分数,但是我看到的所有其他线程都太复杂了,以至于我无法理解,因此请保持简单:我是一个初学者,只需要一个分数。 问题答案: 我建议您搁置。例如: 下次打开程序时,请使用: 它将从磁盘读取。如果需要,可以使用此技术保存
物理内存管理 接下来将首先对实验的执行流程做个介绍,并进一步介绍如何探测物理内存的大小与布局,如何以页为单位来管理计算机系统中的物理内存,如何设计物理内存页的分配算法,最后比较详细地分析了在80386的段页式硬件机制下,ucore操作系统把段式内存管理的功能弱化,并实现以分页为主的页式内存管理的过程。
物理内存管理 物理页 通常,我们在分配物理内存时并不是以字节为单位,而是以一物理页(Frame),即连续的 4 KB 字节为单位分配。我们希望用物理页号(Physical Page Number,PPN)来代表一物理页,实际上代表物理地址范围在 [PPN×4KB,(PPN+1)×4KB)[\text{PPN}\times 4\text{KB},(\text{PPN}+1)\times 4\text
问题内容: 我的磁盘中有40MB的文件,我需要使用字节数组将其“映射”到内存中。 最初,我认为将文件写入ByteArrayOutputStream是最好的方法,但我发现在复制操作期间的某个时刻它会占用约160MB的堆空间。 有人知道不使用三倍于RAM的文件大小的更好方法吗? 更新: 感谢您的回答。我注意到我可以减少内存消耗,告诉ByteArrayOutputStream初始大小比原始文件的大小稍大
笛卡尔坐标系 这个名字你可能不太熟,但是看到下面这个图你应该很熟悉 这其实就是笛卡尔坐标系,一个x轴,一个y轴,都在一个平面上,这个平面一般叫做xy平面,所有二维的笛卡尔坐标系中的点都可以画在这个平面上,比如点:(x, y) 如果想表示三维空间,还需要增加一个z轴 毕达哥拉斯定理与三角函数 毕达哥拉斯定理又叫做勾股定理: h^2 = a^2 + b^2 在直角三角形中sin(θ) = 对边/斜边,