大家好。我已经遇到了大约2周的问题而我不能似乎能够找出它为什么会发生。 那么,是什么情况?
我正在编写 Minecraft 工具,该工具读取保存文件的所有区域文件,并检查它们。如果他们有玩家放置的块,则块所在的块被标记为安全,以后不会被删除;否则在排队过程完成后删除块,因为应该发生几次排队。
该程序似乎运行良好,直到它击中我正在使用的hashset中的961个元素。 该hashset包含字符串,用于确定块是否已被标记为安全。一旦有961个元素,它就像它不能再添加它一样,就好像它的内存不足一样虽然事实并非如此,但我已经为它分配了2gB内存,但仍然没有。我已经测试了很多次,有很多不同的参数,但最高的是961。
在向HashSet添加元素时,它会在961处加满,并且不添加更多元素。也测试了2gB的RAM,但没有运气。
这是我的代码。不要被它淹没,这很简单。
Options
类只是一个加载一些选项的类。不值一提。
Main
类:
public class Main {
Options options = new Options();
Deleter deleter;
public Main() {
deleter = new Deleter(this);
}
public static void main(String[] args) {
Main main = new Main();
try {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
System.out.print("Load world?");
System.out.println("(Y for yes/Q for quit): ");
String s = br.readLine();
while (!s.equalsIgnoreCase("Q")) {
if (s.equalsIgnoreCase("Y")) {
main.deleter.loadWorld();
System.out.println("Enqueue?");
System.out.println("(E for enqueue/Q for quit): ");
s = br.readLine();
while (s.equalsIgnoreCase("E")) { // While user wants to enqueue
main.deleter.enqueue();
System.out.println("Delete?");
System.out.println("(E for enqueue/D for delete/Q for quit)");
s = br.readLine();
}
if (s.equalsIgnoreCase("D")) {
main.deleter.delete();
}
}
} // If input == Quit, do this
} catch (IOException e) {
e.printStackTrace();
}
}
}
Deleter
班
public class Deleter {
private Options options;
private ArrayList<File> files = new ArrayList<>(1000);
private HashSet<String> safeChunks = new HashSet<>(20000);
private ArrayList<Integer> blockIDsList = new ArrayList<>(100);
private int totalChunksEnqueued = 0;
private int chunksEnqueued = 0;
public Deleter(Main main) {
this.options = main.getOptions();
totalChunksEnqueued = 0;
}
public void loadWorld() {
String folderName = options.getSaveFolderFile().getParentFile().getName();
System.out.println("--------Loading world: " + folderName + "--------");
File filesTemp[] = options.getSaveFolderFile().listFiles();
for (File file : filesTemp) {
if (file.getName().endsWith("mca")) {
// RegionFile regionFile = new RegionFile(file);
files.add(file);
}
}
System.out.println("--------World loaded successfully--------");
}
public void enqueue() {
System.out.println("--------Enqueuing--------");
chunksEnqueued = 0;
try {
options.reloadConfig();
} catch (FileNotFoundException e2) {
e2.printStackTrace();
}
int totalFiles = options.getSaveFolderFile().listFiles().length;
int counter = 0;
//START
//Actual enqueuing takes place here
for (File file : files) {
counter++;
System.out.println("Progress: " + counter + "/" + totalFiles + ". Total chunks enqueued: " + totalChunksEnqueued);
RegionFile regionFile = new RegionFile(file);
for (int chunkX = 0; chunkX < 32; chunkX++) {
for (int chunkZ = 0; chunkZ < 32; chunkZ++) {
DataInputStream chunk = regionFile.getChunkDataInputStream(chunkX, chunkZ);
if (regionFile.hasChunk(chunkX, chunkZ)) {
try {
Tag root = Tag.readNamedTag(chunk);
CompoundTag level = root.getCompound("Level");
ListTag sections = level.getList("Sections");
for (int i = 0; i < sections.size(); i++) {
CompoundTag section = (CompoundTag) sections.get(i);
byte[] blocksArray = section.getByteArray("Blocks");
byte[] addsArray = section.getByteArray("Add");
byte Y = section.getByte("Y");
boolean worked = false;
for (int y = 0; y < 16; y++) {
for (int z = 0; z < 16; z++) {
for (int x = 0; x < 16; x++) {
// int realX = regionX * 32 + chunkX * 16 + x;
int realY = Y * 16 + y;
// int realZ = regionZ * 32 + chunkZ * 16 + z;
if (realY >= minY && realY <= maxY) {
// Copied from Chunk Format page.
int BlockPos = (y * 16 * 16) + (z * 16) + (x);
byte BlockID_a = blocksArray[BlockPos];
short BlockID = BlockID_a;
if (addsArray.length != 0) {
byte BlockID_b = nibble4(addsArray, BlockPos);
BlockID = (short) (BlockID_a + (BlockID_b << 8));
}
for (int block : blockIDs) {
if (BlockID == block) {
worked = true;
markSafeChunks(regionFile, chunkX, chunkZ, radius);
break;
}
}
}
if (worked)
break;
}
if (worked)
break;
}
if (worked)
break;
}
if (worked)
break;
}
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
}
try {
regionFile.close();
} catch (IOException e) {
e.printStackTrace();
}
}
//END
System.out.println("Chunks enqueued this time: " + chunksEnqueued);
System.out.println("Total chunks enqueued: " + totalChunksEnqueued);
System.out.println("--------Finished enqueueing--------");
}
public void delete() {
System.out.println("--------Deleting--------");
try {
options.reloadConfig();
} catch (FileNotFoundException e2) {
e2.printStackTrace();
}
int totalFiles = options.getSaveFolderFile().listFiles().length;
//START
// Deletion takes place here
for (File file : files) {
RegionFile regionFile = new RegionFile(file);
// You are now in a region file.
counter++;
System.out.println("Progress: " + counter + "/" + totalFiles);
for (int chunkX = 0; chunkX < 32; chunkX++) {
for (int chunkZ = 0; chunkZ < 32; chunkZ++) {
if (!safeChunks.contains("" + chunkX + "_" + chunkZ) && regionFile.hasChunk(chunkX, chunkZ)) {
try {
regionFile.deleteChunk(chunkX, chunkZ);
chunksDeleted++;
} catch (IOException e1) {
e1.printStackTrace();
return;
}
}
}
}
try {
regionFile.close();
} catch (IOException e2) {
e2.printStackTrace();
}
}
//END
System.out.println("Chunks deleted: " + chunksDeleted);
System.out.println("--------Finished enqueueing--------");
}
private synchronized void markSafeChunks(RegionFile regionFile, int chunkX, int chunkZ, int radius) {
if (radius == 0)
safeChunks.add("" + chunkX + "_" + chunkZ);
else
for (int surX = chunkX - radius; surX <= chunkX + radius; surX++) {
for (int surZ = chunkZ - radius; surZ <= chunkZ + radius; surZ++) {
boolean b = surX > chunkX / 32 && surX < chunkX / 32 + 32;
b &= surZ > chunkZ / 32 && surZ < chunkZ / 32 + 32;
if (b && regionFile.hasChunk(surX, surZ) && !safeChunks.contains("" + surX + "_" + surZ)) {
safeChunks.add("" + surX + "_" + surZ);
chunksEnqueued++;
totalChunksEnqueued++;
}
}
}
}
为什么会发生这种961天花板问题?
答案 0 :(得分:0)
HashSet的容量总是2的幂,你可以添加超过10亿个元素。但是,它确实忽略了重复,所以如果你继续添加元素,但这些元素已经在集合中,它不会增加大小。
如果你没有得到OutOfMemoryError
它就没有内存不足。
BTW打破多个循环的简单方法是使用标签,例如
outer:
while (something)
while (nested)
while (moreNested) {
//
if (condition)
break outer;
}
这意味着您不需要working
变量。