为什么这种方法占用这么多内存?

Why this method takes so much memory?

我正在尝试解开这个谜团,为什么这种创建目录的方法会占用这么多内存(大约 530MB PS Eden Space)。方法执行后,GC 会清理一些内存,但之后仍会保留一些内存。但分配的内存总是保持不变(大约 700MB 分配所有池)。看来我没有取消引用对象:(

如果有人能给我一些处理建议,那就太好了。

public void writeDir(File root, ArrayList<String> hardwareList, ArrayList<String> detectionListFormated, ArrayList<String> siteName, int depth) {
if (depth == 1) {
        return;
    }
    if (depth == 2) {
        for (int i = 0; i < listToDestroy.size(); i++) {
            String toBeFormated = listToDestroy.get(i);
            String toBeTrimmed = toBeFormated.replace("ä", "ae").replace("ß", "ss").replace("ü", "ue").replace("ö", "oe").trim();
            String s = trimLastChar(toBeTrimmed);
            int index = s.indexOf("_");
            if (s.charAt(index + 1) == this.stationNumber) {
                if (s.contains("Manuelle Gruppe")) {
                    File subdir = new File(root, s);
                    File samePath = new File(root, "");
                    subdir.mkdir();
                    detectionListFormated.remove(i);
                    listToDestroy.remove(i);
                    writeDir(samePath, hardwareList, detectionListFormated, siteName, depth);

                } else if (s.contains("Automatische Gruppe")) {
                    File subdir = new File(root, s);
                    File samePath = new File(root, "");
                    subdir.mkdir();
                    detectionListFormated.remove(i);
                    listToDestroy.remove(i);
                    writeDir(samePath, hardwareList, detectionListFormated, siteName, depth);
                } else if (s.contains("Abschnitt")) {
                    writeDir(root.getParentFile(), hardwareList, detectionListFormated, siteName, depth + 1);
                } else if (s.contains("Stations-Objekt")) {
                    writeDir(root.getParentFile().getParentFile(), hardwareList, detectionListFormated, siteName, depth + 2);
                }
            }
        }
    }
    if (depth == 3) {
        for (int i = 0; i < listToDestroy.size(); i++) {
            String toBeFormated = listToDestroy.get(i);
            String toBeTrimmed = toBeFormated.replace("ä", "ae").replace("ß", "ss").replace("ü", "ue").replace("ö", "oe").trim();
            String s = trimLastChar(toBeTrimmed);
            int index = s.indexOf("_");
            if (s.charAt(index + 1) == stationNumber) {
                if (s.contains("Abschnitt")) {
                    File subdir = new File(root, s);
                    subdir.mkdir();
                    detectionListFormated.remove(s);
                    listToDestroy.remove(i);
                    writeDir(subdir, hardwareList, detectionListFormated, siteName, depth - 1);
                } else if (s.contains("Detektions-Objekt")) {
                    writeDir(root.getParentFile(), hardwareList, detectionListFormated, siteName, depth + 1);
                } else if (s.contains("Stations-Objekt")) {
                    writeDir(root.getParentFile(), hardwareList, detectionListFormated, siteName, depth + 1);
                }
            }
        }
    }

    if (depth == 4) {
        for (int i = 0; i < listToDestroy.size(); i++) {
            String toBeFormated = listToDestroy.get(i);
            String toBeTrimmed = toBeFormated.replace("ä", "ae").replace("ß", "ss").replace("ü", "ue").replace("ö", "oe").trim();
            String s = trimLastChar(toBeTrimmed);
            int index = s.indexOf("_");
            if (s.charAt(index + 1) == stationNumber) {
                if (s.contains("Stations-Objekt")) {
                    File subdir = new File(root, s);
                    subdir.mkdir();
                    listToDestroy.remove(i);
                    detectionListFormated.remove(i);
                    // if added it uses literaly no memory at allSystem.gc();
                    writeDir(root, hardwareList, detectionListFormated, siteName, depth - 3);
                } else if (s.contains("Detektions-Objekt")) {
                    File subdir = new File(root, s);
                    subdir.mkdir();
                    listToDestroy.remove(i);
                    detectionListFormated.remove(i);
                    // if added it uses literaly no memory at allSystem.gc();
                    writeDir(subdir, hardwareList, detectionListFormated, siteName, depth - 1);
                }
            }
        }
    }
    if (depth == 5) {
        for (String s : hardwareList) {
            String toBeFormated = s;
            String toBeTrimmed = toBeFormated.replace("ä", "ae").replace("ß", "ss").replace("ü", "ue").replace("ö", "oe").trim();
            String a = trimLastChar(toBeTrimmed);
            File subdir = new File(root, a);
            subdir.mkdir();
            this.stationNumber = a.charAt(0);
            // if added it uses literaly no memory at allSystem.gc();
            writeDir(subdir, hardwareList, detectionListFormated, siteName, depth - 1);
        }
    }
    if (depth == 6) {
        for (String s : siteName) {
            String toBeFormated = s;
            String toBeTrimmed = toBeFormated.replace("ä", "ae").replace("ß", "ss").replace("ü", "ue").replace("ö", "oe").trim();
            String a = trimLastChar(toBeTrimmed);
            File subdir = new File(root, a);
            subdir.mkdirs();
            listToDestroy = new CopyOnWriteArrayList<>(detectionListFormated);
            ArrayList<String> test = new ArrayList<>(listToDestroy);
            // if added it uses literaly no memory at allSystem.gc();
            writeDir(subdir, hardwareList, test, siteName, depth - 1);
        }
    }
}
}

谢谢:)

您正在使用递归。这意味着您在方法内调用方法本身。

例如:你调用方法,然后它用if语句看它是什么深度,在条件下再次调用方法。但是第一个方法的执行还没有完成,它只是被暂停了,因为新的方法调用是 运行。 这会创建一堆方法调用,可以说是嵌套。每次调用都会有自己的变量,都占用内存..一次又一次...你不应该在它自己内部调用方法!

这是真的,因为您不是在循环中执行此操作,所以您将维护您下方堆栈中的任何内容。我不相信递归是这里的主要问题。我的意思是你只有 6 个深度级别,所以堆栈上最多有 6 个实例。

您是否考虑过使用 nio 库而不是旧的 'io' 库来执行此操作。旧 io 库的 cited problems 之一是它在处理大目录时遇到问题,这与资源处理直接相关。

也就是说,这可以通过循环或 Stack 迭代完成,这也会提高一些内存效率。此外,在后面的 if 语句中使用 else if