Home > Software engineering >  A single bigger variable consumes more memory than few other variables, even though the sum of the s
A single bigger variable consumes more memory than few other variables, even though the sum of the s

Time:11-25

Let's say we have 'a' holding a list of N values. And we also have 'b', 'c', and 'd', where the sum of them are also holding N.

In terms of memory consumption is 'a' consuming more than the sum of 'b c d'?

CodePudding user response:

Who can say? Capacity != size. But all else being equal, 3 separate ArrayLists takes more memory than one ArrayList, because the list structure itself takes space apart from what it contains.

I specifically call out ArrayList for this example, because it's conceptually simple. No doubt one can invent structures implementing the List interface where the converse is true: i.e., memory usage goes up faster than what it contains.

Your terminology is wrong, though. Each reference variable (a, b, c, d) is exactly the same size: one reference. It is the referenced objects that have different sizes.

CodePudding user response:

ArrayList is a class which holds a backing Array to contain its data. The backing Array may be exactly the same size as the data or it could be many times larger. In this example, a is much bigger because its backing array has size 5000 and the backing arrays of the others are all of size 1:

fun example1() {
    val values = arrayOf(1, 2, 3)
    
    val a = ArrayList<Int>(5000).apply {
        addAll(values)
    }
    
    val b = arrayListOf(values[0])
    val c = arrayListOf(values[1])
    val d = arrayListOf(values[2])
}

But if you make the backing arrays exactly the same size as the data, then the memory of b, c, and d will add up to a few more bytes than a because of the other memory used per instance of the class. ArrayList holds an int size parameter and there also some base memory overhead for an instance of any class.

fun example2() {
    val values = arrayOf(1, 2, 3)

    val a = arrayListOf(*values)

    val b = arrayListOf(values[0])
    val c = arrayListOf(values[1])
    val d = arrayListOf(values[2])
}

If we use LinkedList, there is no backing array, so memory use scales linearly with the amount of data. Same as example 2, there will be a few more bytes for the additional instances.

fun example3() {
    val values = arrayOf(1, 2, 3)

    val a = values.toCollection(LinkedList())

    val b = LinkedList<Int>().apply { add(values[0]) }
    val c = LinkedList<Int>().apply { add(values[1]) }
    val d = LinkedList<Int>().apply { add(values[2]) }
}

There are also sublists, which are simply views of the data from another List. Here the comparison is murky, because b, c, and d are sharing the same backing array as a uses.

fun example4() {
    val a = (0..999).toCollection(ArrayList(1000))

    val b = a.subList(0, 334)
    val c = a.subList(334,667)
    val d = a.subList(667,1000)
}
  • Related