【问题标题】:Why this method takes so much memory?为什么这种方法占用这么多内存?
【发布时间】:2023-10-08 18:01:01
【问题描述】:

我试图解决这个创建目录的方法为什么要使用这么多内存(大约 530MB PS 伊甸园空间)的谜团。方法执行后,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);
        }
    }
}
}

谢谢:)

【问题讨论】:

  • 可能文件太多?
  • 它创建了 220 个文件夹。我不认为这应该是问题。我希望它创建 n 个文件
  • 您知道使用CopyOnWriteArrayList 意味着每当您remove(或对其进行任何其他写入操作)时都会有一个新的列表副本?

标签: java file methods arraylist mkdir


【解决方案1】:

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

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

【讨论】:

  • 这种任务有更好的选择吗?
  • @Matthijs you shouldn't call a method within itself! 这是一个大胆的声明!递归可以占有一席之地。
  • 没错,递归可以带来好处。不是在这种情况下,他正在添加和减去他的变量..可能会用它创建一个无限循环。
  • 易于实施的好处。递归(逻辑上)遍历目录结构是有意义的,即使从性能的角度来看它没有意义。
【解决方案2】:

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

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

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

【讨论】:

  • 他的可变深度有时会被改变。它有 + 但 - 也......创造了无限循环的可能性。