Hashet最大尺寸似乎是961

时间:2016-09-06 15:03:42

标签: java minecraft hashset

简介

大家好。我已经遇到了大约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天花板问题?

1 个答案:

答案 0 :(得分:0)

HashSet的容量总是2的幂,你可以添加超过10亿个元素。但是,它确实忽略了重复,所以如果你继续添加元素,但这些元素已经在集合中,它不会增加大小。

如果你没有得到OutOfMemoryError它就没有内存不足。

BTW打破多个循环的简单方法是使用标签,例如

outer:
while (something)
   while (nested)
      while (moreNested) {
         //
         if (condition)
             break outer;
      }

这意味着您不需要working变量。