JAVA - 内存不足 - 体素世界生成
JAVA - Out Of Memory - Voxel World Generation
目前我有这个用于代码,我的游戏要么在生成(超过 GB)时使用大量内存,要么如果我将其设置得较低,它会给出
WORLD_SIZE_X & WORLD_SIZE_Z = 256;
WORLD_SIZE_Y = 128;
有谁知道我可以如何改进它以使其不使用那么多 RAM?
谢谢! :)
public void generate() {
for(int xP = 0; xP < WORLD_SIZE_X; xP++) {
for(int zP = 0; zP < WORLD_SIZE_Z; zP++) {
for(int yP = 0; yP < WORLD_SIZE_Y; yP++) {
try {
blocks[xP][yP][zP] = new BlockAir();
if(yP == 4) {
blocks[xP][yP][zP] = new BlockGrass();
}
if(yP < 4) {
blocks[xP][yP][zP] = new BlockDirt();
}
if(yP == 0) {
blocks[xP][yP][zP] = new BlockUnbreakable();
}
} catch(Exception e) {}
}
//Tree Generation :D
Random rX = new Random();
Random rZ = new Random();
if(rX.nextInt(WORLD_SIZE_X) < WORLD_SIZE_X / 6 && rZ.nextInt(WORLD_SIZE_Z) < WORLD_SIZE_Z / 6) {
for(int j = 0; j < 5; j++) {
blocks[xP][5 + j][zP] = new BlockLog();
}
}
}
}
generated = true;
}
延迟创建对象,直到您确实需要访问这些体素之一。您可以编写一个方法(我假设 Block 是所有 Block 类 的公共子类):
Block getBlockAt( int x, int y, int z )
使用类似于三重循环中的代码,加上使用哈希映射 Map<Integer,Block>
来存储随机内容,例如树:从 x、y 和 z 计算一个整数 (x*128 + y)*256 + z
并将其用作键。
此外,考虑到对于所有 "air"、"log"、"dirt" 块,您可能不需要单独的对象,除非必须在某个块处更改某些内容。在那之前,共享一个对象。
因为你只是给出一小段代码,我可以给你两个建议:
压缩对象大小。看起来很愚蠢但很容易做到。试想一下,您的记忆中有数千个对象。如果每个人都能压缩一半大小,就可以节省一半内存:).
需要的时候给数组赋值就行了。如果你真的需要一个分配的数组,有时它是行不通的。因此,只需尽可能少地为数组中的元素赋值。如果你能告诉我更多的代码,我可以帮助你更多。
您确定问题出在这个方法中吗?除非 Block 对象真的很大,否则 256*256*128 ~= 8M 对象应该不需要 1 GB ...
就是说,如果块不保持状态,使用枚举(甚至字节)会更节省内存,因为我们不需要为每个块单独的对象:
enum Block {
air, grass, dirt, log, unbreakable;
}
Block[][][] map = ...
目前我有这个用于代码,我的游戏要么在生成(超过 GB)时使用大量内存,要么如果我将其设置得较低,它会给出
WORLD_SIZE_X & WORLD_SIZE_Z = 256;
WORLD_SIZE_Y = 128;
有谁知道我可以如何改进它以使其不使用那么多 RAM?
谢谢! :)
public void generate() {
for(int xP = 0; xP < WORLD_SIZE_X; xP++) {
for(int zP = 0; zP < WORLD_SIZE_Z; zP++) {
for(int yP = 0; yP < WORLD_SIZE_Y; yP++) {
try {
blocks[xP][yP][zP] = new BlockAir();
if(yP == 4) {
blocks[xP][yP][zP] = new BlockGrass();
}
if(yP < 4) {
blocks[xP][yP][zP] = new BlockDirt();
}
if(yP == 0) {
blocks[xP][yP][zP] = new BlockUnbreakable();
}
} catch(Exception e) {}
}
//Tree Generation :D
Random rX = new Random();
Random rZ = new Random();
if(rX.nextInt(WORLD_SIZE_X) < WORLD_SIZE_X / 6 && rZ.nextInt(WORLD_SIZE_Z) < WORLD_SIZE_Z / 6) {
for(int j = 0; j < 5; j++) {
blocks[xP][5 + j][zP] = new BlockLog();
}
}
}
}
generated = true;
}
延迟创建对象,直到您确实需要访问这些体素之一。您可以编写一个方法(我假设 Block 是所有 Block 类 的公共子类):
Block getBlockAt( int x, int y, int z )
使用类似于三重循环中的代码,加上使用哈希映射 Map<Integer,Block>
来存储随机内容,例如树:从 x、y 和 z 计算一个整数 (x*128 + y)*256 + z
并将其用作键。
此外,考虑到对于所有 "air"、"log"、"dirt" 块,您可能不需要单独的对象,除非必须在某个块处更改某些内容。在那之前,共享一个对象。
因为你只是给出一小段代码,我可以给你两个建议:
压缩对象大小。看起来很愚蠢但很容易做到。试想一下,您的记忆中有数千个对象。如果每个人都能压缩一半大小,就可以节省一半内存:).
需要的时候给数组赋值就行了。如果你真的需要一个分配的数组,有时它是行不通的。因此,只需尽可能少地为数组中的元素赋值。如果你能告诉我更多的代码,我可以帮助你更多。
您确定问题出在这个方法中吗?除非 Block 对象真的很大,否则 256*256*128 ~= 8M 对象应该不需要 1 GB ...
就是说,如果块不保持状态,使用枚举(甚至字节)会更节省内存,因为我们不需要为每个块单独的对象:
enum Block {
air, grass, dirt, log, unbreakable;
}
Block[][][] map = ...