I'm profiling my application and java.nio.file.Files is appearing as the top hotspot for memory usage (profiled with JProfile).
This doesn't make sense to me because the application is running a lot of XSLT transformations and storing the results in memory. While it is showing up as a top-contender for memory usage, I wouldn't expect it to be surpassed by a java.nio.file.Files.exists()
call.
This is the code in question that's causing the memory hotspot:
public static FileStatus getFileStatus(Path path) {
try {
var exists = Files.exists(path);
var isDirectory = exists && Files.isDirectory(path);
var lastModified = exists ? Files.getLastModifiedTime(path).toMillis() : 0;
var size = exists ? Files.size(path) : 0;
return new FileStatus(exists, isDirectory, lastModified, size);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
Why is Files.exists()
taking up so much memory, and is there a way fix the memory usage? This is running on AdoptOpenJDK 11 and running on Windows 10.
I couldn't explain why one call to Files.exists
has high memory impact - but it is a file system access so do expect it to behave as would accessing a file every time.
However, all those calls you use make use of Files.readAttributes internally, so you can reduce 3x filesystem accesses (and allocations for same) by changing getFileStatus
to make one readAttributes
call:
public static FileStatus getFileStatus(Path path) {
try {
BasicFileAttributes attrs = Files.readAttributes(path, BasicFileAttributes.class);
return new FileStatus(true,
attrs.isDirectory(),
attrs.lastModifiedTime().toMillis(),
attrs.isDirectory() ? 0L : attrs.size());
} catch (IOException e) {
// Does not exist:
return new FileStatus(false, false, 0L, 0L);
}
}
Note: On Windows (and WSL), Files.size
on a directory can return non-zero. This is not the size of the contents. If you want to keep that behaviour, use attrs.size()
as the last parameter to new FileStatus()