简体   繁体   中英

Free unused RAM in Java

I have a Java class that allocates all files within a directory (6GB). Then for each file, does some text processing. When I check the ram usage, I can see that when I finish from a file and start to the next file, RAM does not get rid of the previous file - bad garbage collection, I guess. Is there a way to programatically free the finished file and its data?

public void fromDirectory(String path) {

        File folder = new File(path);
        disFile = path + "/dis.txt";
        if (folder.isDirectory()) {
            File[] listOfFiles = folder.listFiles();

            for (int i = 0; i < listOfFiles.length; i++) {
                File file = listOfFiles[i];
                if (file.isFile() && file.getName().contains("log")) {
                    System.out.println("The file will be processed is: "
                            + file.getPath());
                    forEachFile(file.getPath());
                    //Runtime.getRuntime().exec("purge");
                    //System.gc();

                } else
                    System.out.println("The file " + file.getName()
                            + " doesn't contain log");
            }

        } else {
            System.out.println("The path: " + path + " is not a directory");
        }

}

private void forEachFile(String filePath) {
    File in = new File(filePath);
    File out = new File(disFile);

    try {
        out.createNewFile();
        FileWriter fw = new FileWriter(out.getAbsoluteFile());
        BufferedWriter bw = new BufferedWriter(fw);
        BufferedReader reader = new BufferedReader(new FileReader(in));

        String line = null;
        while ((line = reader.readLine()) != null) {

            if (line.toLowerCase().contains("keyword")) {
                bw.write(line);
                bw.newLine();
                numberOfLines++;
            }
        }
        reader.close();
        bw.close();

    } catch (IOException e) {
        e.printStackTrace();
    }
}

You can strongly suggests the VM to do a garbage collection by calling System.gc() . It is generally considered a code-smell to do so.

I think you are mistaking two things here: JVMs memory allocation and realy memory usage within allocated space.

JVM may allocate a lot of memory and not free it even after the objects that were using it were garbaged internally. It may be freed after some time or not freed at all.

You could try to reduce the memory footprint of your application, for example by not using toLowerCase, since it creates a new object. Maybe a precompiled regex search would be faster?

Using System.gc() as you did it, in your case, in my opinion, is acceptable. Whether it helps anything - I don't know.

As long as you have a lot of memory available and Java doesn't slow down because of too not being able to allocate more, I would leave it as it is. The code looks fine.

Even if you are right about checking the memory from some profiler and deducing "correctly" that the file remains in memory why do you think it should be released immediately?

The JVM will garbage collect when the memory is running out (depending on the JVM configuration) not when developers think it should.

Also judging from your question I doubt if you used a profiler or a similar tool gauge JVM memory usage. Instead it's more likely you checked the memory being used by the JVM as a whole.

Also you shouldn't worry about these things unless you are encountering out of memory errors.

As stated, the garbage collector runs when there is no more memory available. If you have 10 files of 100MB each, and you set your heap to 4GB , then chances are that you simply won't ever get any GC.

Now, for the "free the finished file and its data" part, you cannot really do this by yourself, and should not try to do so.

  • If you want your application to be memory-efficient, then you can just set the maximum heap size to a small value.
  • On the other hand, if you want your application to be really fast, then you don't want to suffer from any GC, therefore eliminating every System.gc() call and giving your heap as much memory as possible.

Trying to free memory yourself mean giving too much memory to your heap (your app is not memory-efficient) and triggering GC yourself (your app is not time-efficient either).

Note that in some cases, the JVM can give back memory to the OS. For instance, with G1, it will, but with CMS, it won't. See this article for more details.

Finally, if you use Java7, you should wrap your InputStream / OutputStream in a try-with-resources. Or, at least, wrap the .close() in a finally block.

Hope that helps !

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM