[ Edit2: The original answer is left in italics at the end of this post]
After your explanation in the comments, I ran your code on a Windows machine (Java 1.6), and here are my conclusions (the numbers are taken from VisualVM, OS memory, as can be seen from the task manager):
Example with a size of 40K, writing to 500K files (no parameters for JVM): Heap used: ~ 4M, Total Heap: 16M, OS memory: ~ 16M
Example with a size of 40 M, writing to 500 files (parameters for JVM -Xms128m -Xmx512m. Without parameters I get an OutOfMemory error when creating a StringBuilder): Heap used: ~ 265M, heap size: ~ 365M, OS memory: ~ 365M
Especially from the second example, you can see that my initial explanation is still worth it. Yes, someone would expect that most of the memory would be freed, since the byte[] from the BufferedOutputStream would be in the first generation space (objects with a short circuit), but this a) will not happen immediately and b) when the GC decides to hit ( this is actually in my case), yes, he will try to clear the memory, but he can clear as much memory as he sees fit, and not necessarily all of that. GC does not provide any guarantors you can count on.
So, in general, you should give the JVM as much memory as is comfortable with you. If you need to keep low memory for special functions, you should try the strategy, as an example of the code that I gave below in my original answer, i.e. Just don't create all those byte[] objects.
Now in your case with CentOS, it looks like the JVM is behaving strangely. Perhaps we could talk about buggy or poor implementation. To classify it as a leak / error, you should try using -Xmx to limit the heap. Also try that Peter Laurie suggested not creating a BufferedOutputStream at all (in the case of a small file), since you just write all the bytes at once.
If it still exceeds the memory limit, you are experiencing a leak and probably should find an error. (You can still complain, and they can optimize it in the future).
[Edit1: the answer below assumes that the OP code performed as many read operations as many write operations, so memory usage was warranted. OP explained that this is not so, therefore, did not answer his question
"... my virtual memory is 15 GB ..." If you give the JVM so much memory, why should it try to start the GC? As for the JVM, it is allowed to receive so much memory from the system and run the GC only when it believes that it is suitable. Each execution of a BufferedOutputStream by default allocate an 8 KB buffer. The JVM will try to return this memory only when necessary. This is the expected behavior. Do not confuse the memory that you see is free from the system point of view and from the point of view of the JVM. As far as the system is concerned, memory is allocated and will be released when the JVM shuts down. As for the JVM, all byte[] arrays allocated from the BufferedOutputStream are no longer used, this is "free" memory and will be fixed if necessary. If for some reason you do not want this behavior, you can try the following: Extend the BufferedOutputStream class (for example, create the ReusableBufferedOutputStream class) and add a new method, for example. reUseWithStream(OutputStream os) . Then this method will clear the internal byte[] , close and close the previous stream, reset any variables used and set a new stream. Then your code will be as follows:
// intialize once ReusableBufferedOutputStream fs = new ReusableBufferedOutputStream(); for (int i=0; i < fileCount; i ++) { String path = String.format("%s%sTestFile_%d.txt", dir, File.separator, i); //set the new stream to be buffered and read fs.reUseWithStream(new FileOutputStream(path)); fs.write(this._buf, 0, this._buf.length); // this._buf was allocated once, 40K long contain text } fs.close(); // Close the stream after we are done
Using the above approach, you will avoid creating many byte[] . However, I do not see any problems with the expected behavior, and you do not mention any problem other than "I see that it takes too much memory." You used it anyway to use it.]