这种方法占用这么多内存的原因是什么?

What is the reason for this method to take so much memory?

我正在尝试调试此方法,但似乎没有任何效果...
我怀疑在条件语句 pathName.add() 中有麻烦。此方法执行后占用50MB,再执行一次占用150MB,直至达到800MB。但是都分配了space。为什么 gc 不清理这个烂摊子???

P.s 此方法根据使用条件语句构建的给定路径创建目录

P.s P.s writeDir(...) 方法从 actionListener 中调用(当 gui ic 上的按钮被点击时)。按钮可以经常点击

P.s P.s P.s 我已经尝试了 Andreas 的建议并且部分奏效了。在调用 pathName.clean() 后,eden space 被丢弃但分配的 space 仍在增长,达到最大值。

会对您的意见感兴趣 :) 谢谢

Calling writeDir(...)

startButton.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
            try {
                        progress(0);
                        XMLSaxLogic stax = new XMLSaxLogic(xmlPath);

                        DetectionFilter detectionFilter = new DetectionFilter(stax.getObjets());
                        try {
                            WriteFile writeFile = new WriteFile(detectionFilter.getDetectionList());
                            writeFile.writeDir(savedDirPath, detectionFilter.getHardwareList(), stax.getSiteName());
                            progress(100);
                        } catch (Exception a) {
                            System.out.println(a.getLocalizedMessage());
                        }
                        GetFileCount getFileCount = new GetFileCount(savedDirPath, detectionFilter.getDetectionList(), combo.getSelectedIndex());

                        getFileCount.getFile(savedDirPath.getAbsoluteFile().toString());
                    } catch (Exception a) {
                        System.out.println(a.getLocalizedMessage());
                    }
}
}

writeDir(...)

   private ArrayList<String> detectList;
   private String detection = null;
   private String build = null;
   private Set<String> pathName = new LinkedHashSet<>();
   public WriteFile(ArrayList<String> detectList) {
       this.detectList = detectList;
   }
public void writeDir(File root, ArrayList<String> sevenElementList, ArrayList<String> oneElementList) {

    for (String site : oneElementList) {
        for (String s : sevenElementList) {
            int indexx = s.indexOf("_");
            int id = Character.getNumericValue(s.charAt(indexHardware - 1));

            for (String detectionList : detectList) {
                int index = detectionList.indexOf("_");
                int sId = Character.getNumericValue(detectionList.charAt(index + 1));

                if (detectionList.contains("Apple") && sId == id) {
                    detection = site.trim() + "/" + s + "/" + detectionList.trim();
                    pathName.add(format(detection));
                } else if (detectionList.contains("Banana") && sId == id) {
                    build = detection.trim() + "/" + detectionList.trim();
                    pathName.add(format(build.trim()));
                } else if (detectionList.contains("nananana") && sId == id) {
                    pathName.add(format(build.trim() + "/" + detectionList.trim()));
                } else if (detectionList.contains("Watermelone") && sId == id) {
                    pathName.add(format(build.trim() + "/" + detectionList));
                } else if (detectionList.contains("Orange") && sId == id) {
                    pathName.add(format(site.trim() + "/" + s.trim() + "/" + detectionList.trim()));
                }
            }
        }
    }
    createDirTest(pathName, root);
}
private void createDirTest(Set<String> pathArray, File root) {
    for (String s : pathArray) {
        File subdir = new File(root, s);
        subdir.mkdirs();
    }
}

private String format(String toBeFormated) {
    String toBeTrimmed = trimLastChar(toBeFormated.replace("ä", "ae").replace("ß", "ss").replace("ü", "ue").replace("ö", "oe").trim());
    return toBeTrimmed;
}

您将所有路径存储在 Set<String> pathName 字段 中,即使您显示的代码部分仅将其用作 [=11= 的参数].

Set 使用的所有内存将不会释放,直到您 1) 清除集合,或 2) 停止引用相关 class 的实例。

在未来某个未指定的时间点,JVM GC 将回收 space。

如果你真的需要它作为一个字段,为什么要作为参数传递? createDirTest 有权访问该字段。如果不是,则删除该字段,并声明一个局部变量。


更新

根据评论,程序在使用 800MB 后仍保持 运行。

在那种情况下,这就是 JVM 的工作方式。该程序可以正常运行,而您只是觉得自己遇到了问题。你没有。

您可以通过在 actionPerformed() 方法的末尾调用 System.gc() 强制 进行完整的垃圾回收,after try 语句,但只是为了确认 full GC 释放了所有使用的内存。仅用于测试,不要将 gc() 调用留在那里。

要查看 GC 运行情况,您可以在 运行 代码中添加 -Xloggc:path/to/file.log-XX:+PrintGCDetails -XX:+PrintGCTimeStamps 选项。有关详细信息,请参阅 documentation。同样,仅用于测试。

在意识到单击开始按钮创建了新对象 WriteFile writeFile = new WriteFile(...)GetFileCount getFileCount = new GetFileCount(...)XMLSaxLogic stax = new XMLSaxLogic(...) 之后,我已将 thouse 对象的创建移到别处(那里将只创建一个对象! ).

现在没有内存问题,即使连续点击按钮也不会超过 150MB。一切看起来都很正常。但我确定代码中仍然存在一些引用问题,但由于调试,主要问题已经消失:)

经验教训:避免过于频繁地创建太多对象^^

非常感谢@Andreas 和@ouflak!