Search code examples
javakotlinruntimeheap

Java/Kotlin Heap Size


I'm trying to understand the space objects take up in memory in the heap when initialized, but I can't find definitive information on this, so my question is given these 2 examples, with 3 classes each, what would be the order of size taken up by each instance? I know every int takes up a space of 4 bytes, but does not declaring it as a val or var alter this as in class C? Does having a getter method also alter it as in class A?

class A (
    val x: Int = 999,
    val y: Int get() = 999,
    var z: Int = -1
)

class B (
    val x: Int = 0,
    val y: Int = 999,
    val z: Int = -1
)

class C (
    x: Int = 999,
    y: Int = 999,
    z: Int = 999
)

In this second example, does having a function declared like in A affect the size? What about in B where there will only be the class parameters called? How about C where there are both parameters and getters, but also a function inside the class with its own parameters and variables?

class A {
  fun foo() = 123456
  val nr: Int get() = 7658894
  val foo: Int get() = nr

  class B(val bar: Int, val foo: Int)

  class C(val bar: Int) {
    val nr: Int get() = bar
    fun foo() = nr
    fun oper(num: Int): Int {
      val x = num + 1
      val y = num - 1
      return x * y
    }
  }
}

Solution

  • This is a complicated question with many variables to consider so I'll make some assumptions

    For the standard Hotspot JVM (versions <= 22, this will apply to future versions too, but not forever. No Lilliput)

    32 Bit Systems

    • The header of an object takes 8 bytes
    • The primitive fields take their standard sizes
      • byte = 1
      • short = 2
      • char = 2
      • int = 4
      • long = 8
      • float = 4
      • double = 8
    • Reference (objects) fields take 4 bytes
    • The object size is padded (rounded up) to the nearest 4 bytes

    64 Bit Systems

    • The header of an object takes 12 bytes
    • The primitive fields take their standard sizes
      • Look above
    • Reference (objects) fields take 8 bytes (or 4 bytes when compressed OOPs are used, which is likely for apps with less than 32GB of heap)
    • The class size is padded (rounded up) to the nearest 4 bytes

    So for the following Java class in a 64 bit system with compressed pointers

    class Hello {
        public byte a;
        public String b;
        public int c;
    }
    

    the object size will be 12 + 1 + 4 + 4 = 21 (24 when rounded up to the nearest 8) 24 bytes

    Kotlin Examples

    First Code Block

    Class A

    In class A, the properties x and z are backed by fields and will each take up 4 bytes. Property y is not backed by a field because there is a getter attached to it and takes up no space in object instances

    The total size will be (12 + 4 + 0 + 4) ceil 8 = 24

    Class B

    In class B, all the properties are backed by fields and will each take up 4 bytes.

    The total size will be (12 + 4 + 4 + 4) ceil 8 = 24

    Class C

    In class C, because val or var is not attached to the constructor parameters, that is all they are, constructor parameters. A parameter to a method or constructor is not persisted and can't take up space in the heap.

    The total size will be (12 + 0 + 0 + 0) ceil 8 = 16

    Second Code Block

    Methods in Java and Kotlin take up no extra space in the per instance heap allocation of an object

    Class A

    Class A has no field backed properties (as they have getters) and will only need 16 bytes per instance

    Class B

    Class B has two int field backed properties and will need 24 bytes per instance

    Class C

    Class C has one int field backed property and will need 16 bytes per instance