Skip to main content

Size of a byte in memory - Java



I have heard mixed opinions over the amount of memory that a byte takes up in a java program.





I am aware you can store no more than +127 in a java byte, and the documentation says that a byte is only 8 bits but here I am told that it actually takes up the same amount of memory as an int, and therefore is just a Type that helps in code comprehension and not efficiency.





Can anyone clear this up, and would this be an implementation specific issue?


Comments

  1. Okay, there's been a lot of discussion and not a lot of code :)

    Here's a quick benchmark. It's got the normal caveats when it comes to this kind of thing - testing memory has oddities due to JITting etc, but with suitably large numbers it's useful anyway. It has two types, each with 80 members - LotsOfBytes has 80 bytes, LotsOfInts has 80 ints. We build lots of them, make sure they're not GC'd, and check memory usage:

    class LotsOfBytes
    {
    byte a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, aa, ab, ac, ad, ae, af;
    byte b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, ba, bb, bc, bd, be, bf;
    byte c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, ca, cb, cc, cd, ce, cf;
    byte d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, da, db, dc, dd, de, df;
    byte e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, ea, eb, ec, ed, ee, ef;
    }

    class LotsOfInts
    {
    int a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, aa, ab, ac, ad, ae, af;
    int b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, ba, bb, bc, bd, be, bf;
    int c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, ca, cb, cc, cd, ce, cf;
    int d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, da, db, dc, dd, de, df;
    int e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, ea, eb, ec, ed, ee, ef;
    }


    public class Test
    {
    private static final int SIZE = 1000000;

    public static void main(String[] args) throws Exception
    {
    LotsOfBytes[] first = new LotsOfBytes[SIZE];
    LotsOfInts[] second = new LotsOfInts[SIZE];

    System.gc();
    long startMem = getMemory();

    for (int i=0; i < SIZE; i++)
    {
    first[i] = new LotsOfBytes();
    }

    System.gc();
    long endMem = getMemory();

    System.out.println ("Size for LotsOfBytes: " + (endMem-startMem));
    System.out.println ("Average size: " + ((endMem-startMem) / ((double)SIZE)));

    System.gc();
    startMem = getMemory();
    for (int i=0; i < SIZE; i++)
    {
    second[i] = new LotsOfInts();
    }
    System.gc();
    endMem = getMemory();

    System.out.println ("Size for LotsOfInts: " + (endMem-startMem));
    System.out.println ("Average size: " + ((endMem-startMem) / ((double)SIZE)));

    // Make sure nothing gets collected
    long total = 0;
    for (int i=0; i < SIZE; i++)
    {
    total += first[i].a0 + second[i].a0;
    }
    System.out.println(total);
    }

    private static long getMemory()
    {
    Runtime runtime = Runtime.getRuntime();
    return runtime.totalMemory() - runtime.freeMemory();
    }
    }


    Output on my box:

    Size for LotsOfBytes: 88811688
    Average size: 88.811688
    Size for LotsOfInts: 327076360
    Average size: 327.07636
    0


    So obviously there's some overhead - 8 bytes by the looks of it, although somehow only 7 for LotsOfInts (? like I said, there are oddities here) - but the point is that the byte fields appear to be packed in for LotsOfBytes such that it takes (after overhead removal) only a quarter as much memory as LotsOfInts.

    ReplyDelete
  2. Java is never implementation or platform specific (at least as far as primitive type sizes are concerned). They primitive types are always guaranteed to stay the same no matter what platform you're on. This differs from (and was considered an improvement on) C and C++, where some of the primitive types were platform specific.

    Since it's faster for the underlying operating system to address four (or eight, in a 64-bit system) bytes at a time, the JVM may allocate more bytes to store a primitive byte, but you can still only store values from -128 to 127 in it.

    ReplyDelete
  3. A revealing exercise is to run javap on some code that does simple things with bytes and ints. You'll see bytecodes that expect int parameters operating on bytes, and bytecodes being inserted to co-erce from one to another.

    Note though that arrays of bytes are not stored as arrays of 4-byte values, so a 1024-length byte array will use 1k of memory (Ignoring any overheads).

    ReplyDelete
  4. Yes, a byte variable is in fact 4 bytes in memory. However this doesn't hold true for arrays. A byte array of 20 bytes is in fact only 20 bytes in memory. That is because the Java Bytecode Language only knows ints and longs as number types (so it must handle all numbers as either type of both, 4 bytes or 8 bytes), but it knows arrays with every possible number size (so short arrays are in fact two bytes per entry and byte arrays are in fact one byte per entry).

    ReplyDelete
  5. It depends on how the JVM applies padding etc. An array of bytes will (in any sane system) be packed into 1-byte-per-element, but a class with four byte fields could either be tightly packed or padded onto word boundaries - it's implementation dependent.

    ReplyDelete
  6. You could always use longs and pack the data in yourself to increase efficiency. Then you can always gaurentee you'll be using all 4 bytes.

    ReplyDelete
  7. What you've been told is exactly right. The Java byte code specification only has 4-byte types and 8-byte types.

    byte, char, int, short, boolean, float are all stored in 4 bytes each.

    double and long are stored in 8 bytes.

    However byte code is only half the story. There's also the JVM, which is implementation-specific. There's enough info in Java byte code to determine that a variable was declared as a byte. A JVM implementor may decide to use only a byte, although I think that is highly unlikely.

    ReplyDelete
  8. byte = 8bit =one byte defined by the Java Spec.

    how much memory an byte array needs is not defined by the Spec, nor is defined how much a complex objects needs.

    For the Sun JVM I documented the rules

    here

    Regards,

    Markus

    ReplyDelete
  9. See my MonitoringTools at my site (www.csd.uoc.gr/~andreou)


    class X {
    byte b1, b2, b3...;
    }

    long memoryUsed = MemoryMeasurer.measure(new X());


    (It can be used for more complex objects/object graphs too)

    In Sun's 1.6 JDK, it seems that a byte indeed takes a single byte (in older versions, int ~ byte in terms of memory). But note that even in older versions, byte[] were also packed to one byte per entry.

    Anyway, the point is that there is no need for complex tests like Jon Skeet's above, that only give estimations. We can directly measure the size of an object!

    ReplyDelete
  10. Reading through the above comments, it seems that my conclusion will come as a surprise to many (it is also a surprise to me), so it worths repeating:


    The old size(int) == size(byte) for variables holds no more, at least in Sun's Java 6.


    Instead, size(byte) == 1 byte (!!)

    ReplyDelete
  11. It appears that the answer is likely to depend on your JVM version and probably also the CPU architecture you're running on. The Intel line of CPUs do byte manipulation efficiently (due to its 8-bit CPU history). Some RISC chips require word (4 byte) alignment for many operations. And memory allocation can be different for variables on the stack, fields in a class, and in an array.

    ReplyDelete

Post a Comment

Popular posts from this blog

[韓日関係] 首相含む大幅な内閣改造の可能性…早ければ来月10日ごろ=韓国

div not scrolling properly with slimScroll plugin

I am using the slimScroll plugin for jQuery by Piotr Rochala Which is a great plugin for nice scrollbars on most browsers but I am stuck because I am using it for a chat box and whenever the user appends new text to the boxit does scroll using the .scrollTop() method however the plugin's scrollbar doesnt scroll with it and when the user wants to look though the chat history it will start scrolling from near the top. I have made a quick demo of my situation http://jsfiddle.net/DY9CT/2/ Does anyone know how to solve this problem?

Why does this javascript based printing cause Safari to refresh the page?

The page I am working on has a javascript function executed to print parts of the page. For some reason, printing in Safari, causes the window to somehow update. I say somehow, because it does not really refresh as in reload the page, but rather it starts the "rendering" of the page from start, i.e. scroll to top, flash animations start from 0, and so forth. The effect is reproduced by this fiddle: http://jsfiddle.net/fYmnB/ Clicking the print button and finishing or cancelling a print in Safari causes the screen to "go white" for a sec, which in my real website manifests itself as something "like" a reload. While running print button with, let's say, Firefox, just opens and closes the print dialogue without affecting the fiddle page in any way. Is there something with my way of calling the browsers print method that causes this, or how can it be explained - and preferably, avoided? P.S.: On my real site the same occurs with Chrome. In the ex