interface A{
val v: Int
}
class C1: A{
override val v = 12
}
class C2: A{
override val v get() = 23
}
They both provide “v”, but one keeps it in variable, other returns it by ‘get’ method.
When compiled to JVM code, is there more storage allocated to C2 over C1, due to actually keeping variable v in a field?
For single class instance it may not matter to have class bigger by some 4 bytes, but if I allocate thousands of such classes containing multiple similar variables, I’m interested if way how I implement val has impact on memory consumption.
C1 will indeed keep the value in memory, while C2 will compute it on the fly. In theory. In real life, the difference could be non-existent or even work the other way around because JVM could inline get method or on the contrary scalarize the value.
The general recommendation is not to keep constants in instances, companions are made for that.
It’s not about constants here, it’s implementation of some variable. You can imagine that instead of v variable, there is canBackup variable that needs to be implemented, and in C1 it could be constant, while in C2 it could be run-time computed, or run-time returned constant. Employing companion object for such canBackup variable doesn’t make sense.
I was interested in memory consumption of these two variants, mainly when I need to return constant value - keeping it in val vs returning it in get function. So that I possibly get habit to use get() for lower memory consumption.
C1 allocates 4 bytes for v, C2 doesn’t allocate byte for backing fields, so its allocate 0 plus the allocation of C1 (4 bytes).
You can imagine that instead of v variable, there is canBackup variable that needs to be implemented, and in C1 it could be constant, while in C2 it could be run-time computed, or run-time returned constant.
In such examples none implementations require backing field, there is no value storing a constant in a backing field (C1 class), you can use a plain getter as C2 does.
I would advice you to not care until it is measured to be a problem. In my experience premature optimization leads to complex code without achieving a significant benefit.
Even if you save yourself 100 bytes per object and have 1 million of them, that’s about 100mb of savings, which by todays memory standards is really just peanuts.
It might be needed to save these, but better put your effort into mechanisms to detect such need in the first place before theoretically come up with vary solutions to problems that potentially never arise.
Normally I would agree, but in this case I think it actually makes some sense. I’m often in a situation where I need to do override val v = 12 or override val v get() = 12 and I don’t really care which one I choose. I usually take the first one to save 6 chars of code, but it is almost the same. Maybe it is not a bad idea to get used to using the second option as the preferable one?
Best would be if compiler would optimize it out and not store any field for such constant variable, but currently it seems not to be the case, JVM bytecode shows that it has longer constructor (initializes the field), and slower variable getter function getV by actually reading the field, and not returning constant as it could.
In C2 you add a method that’s why it have memory impact, and performance impact too.
val c1 = C1()
val c2 = C2()
c1.v is faster that c2.v. Because in first case you access directly a field, in second case you call the method. Its a problem of Kotlin, it hides too much things some times. Shorter does not always means easier to understand.
@jhelpgg You’re right about how the property getter is compiled. However, there is no per-instance memory impact from adding a method; it’s (effectively) stored in the single Class object representing your class, and there’s only one of those, no matter how many instances of your class there are.
Also, be very wary of drawing naive conclusions about performance; the JVM heavily optimises code, and so (once it’s warmed up) what’s actually running may not bear much resemblance to the original bytecode. In this case, if it can see that the method is short and never overridden, it’s quite likely to inline it — so it could be faster than accessing a field.
This is totally not true. You call getV() method in both cases. Properties are not fields, technically they are methods (getters and setters) plus optionally fields. Above example compiles to:
class C1 {
private final int v = 12;
public int getV() { return v; }
}
class C2 {
public int getV() { return 12; }
}
But as others said, JVM most probably optimizes it on runtime.
It depends on which JVM it’s run. It may pass through proguard or similar tool, which may optimize it. For Android, JVM code is compiled to dex bytecode, which is run in ART interpreter on device. Such code may be optimized or may not.