[1798637 views]

[]

Odi's astoundingly incomplete notes

New entries | Code

Java's OutputStreamWriter can waste memory

The following little unit test measures the memory usage when you convert from char to byte using an OutputStreamWriter. It does that once without buffering and once with a BufferedWriter wrapped around the stream.
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.lang.management.GarbageCollectorMXBean;
import java.lang.management.ManagementFactory;

import junit.framework.TestCase;


public class StreamTest extends TestCase {
    public void test1() throws Exception {
        Runtime rt = Runtime.getRuntime();

        final int max = 10000;
        File f = File.createTempFile("junit", "tmp");

        int gcs = gcs();
        long used = rt.totalMemory() - rt.freeMemory();
        Writer w = new OutputStreamWriter(new FileOutputStream(f), "UTF-8");
        for (int i=0; i<max; i++) {
            w.write("constant");
        }
        w.close();
        assertEquals("increase -Xms -Xmx", gcs, gcs());
        long used2 = rt.totalMemory() - rt.freeMemory();
        System.out.println("unbuffered: "+ (used2 - used) +" bytes");
        
        f.delete();
        gcs = gcs();
        used = rt.totalMemory() - rt.freeMemory();
        w = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(f), "UTF-8"));
        for (int i=0; i<max; i++) {
            w.write("constant");
        }
        w.close();
        assertEquals("increase -Xms -Xmx", gcs, gcs());
        used2 = rt.totalMemory() - rt.freeMemory();
        System.out.println("buffered: "+ (used2 - used) +" bytes");
        
        System.out.println(System.getProperty("java.runtime.version"));
    }
    
    private int gcs() {
        int sum = 0;
        for (GarbageCollectorMXBean mb : ManagementFactory.getGarbageCollectorMXBeans()) {
            sum += mb.getCollectionCount();
        }
        return sum;
    }
}

The result is surprising:
unbuffered: 943896 bytes
buffered: 0 bytes
1.7.0_45-b18
(The actual numbers depend on the heap size). One would assume that unbuffered writes use no memory, and that buffered writes use the buffer size. However this behaviour suggests that OutputStreamWriter's implementation bears a dirty little secret... And where does the buffer memory go? I can just assume that the VM plays dirty optimization tricks here and quickly allocates the transient buffer from thread-local memory without actually resorting to heap.
posted on 2013-11-12 20:40 UTC in Code | 0 comments | permalink