Must create new object for temporary data?

Hi, before this topic, I talk about my situation. I am making algorithm that using vector many. so I made class like below for easy using.

class Vec2(val x: Float, val y: Float) {
    inline operator fun plus(other: Vec2): Vec2{
        return Vec2(x+other.x, y+other.y)
    }
}

But a new object is created every times when I add two vector. and it it problem for me. because this algorithm is called for rendering. So, at least 60 times called every second and may objects are created.

But I don’t want to use function like below, too. This is not pretty. Moreover, I must keep instance of Vec2 for parameter out of the function. And it will cause hard reading and using memory for temporary data.

fun plus(out: Vec2, in1: Vec2, in2: Vec2)

First, I wonder is there no solution for such a situation? I don’t think this is not a rare case. Or creating many object as local instance is no problem? ( If no problem, why? )

Second, Why JVM based languages not allow to make object on stack memory, even if the object is only used for local temporary data. Is there any plan of Kotlin?

1 Like

The answer is that this is not really a problem. Unless you are running on a very old version of the JVM it will simply optimize this away. The JVM will in many cases allocate objects on the stack if it is possible. So to answer your second question, it is not part of the language to define this, because it is already done automatically by the JVM.
Another problem you allude to is garbage collection (many temp objects), but since they have a short live cycle they aren’t a problem there since most modern garbage collectors use a system where most of the work is done for long living objects and short living objects are close to free.

In my experience you don’t have to worry unless your profiling shows that this is your actual bottle neck.

3 Likes

Thanks for fast reply. I google about GC after reading your reply. And find some nice texts for this topic.

Second text says that objects that not escape a method scope are become inline by compiler. so my worry was solved ( I don’t know kotlin compiler too, but I belive ). And even short-live objects that escape a method scope, but fast un-referenced, get collected fast with cheap cost. thanks.

for a “problem” like this where you are not sure how negatively performance is impacted and you want to give yourself that extra bit of misguided reassurance that you am somehow smarter than the JIT compiler at optimization, you can use inline class in kotlin.

An inline class is similar to a data class in that it must have a property parameter. The difference is that it must have only one single parameter and it must be a val. An inline class can also not have any “concrete properties” in that it cannot have anything like this val memberOfInlineClass: Type = Type("data") and it must use custom getters instead.

This idea I am about to explain is where inline class gets it’s supposed power. inline class is optimized as it’s val parameter type because it is essentially that type and all your functions inside of it will have to rely on this parameter to get their functions. If you are using an inline class as itself and not any potential interfaces it implements, ti will be optimized at that type. If you use it as any of it’s interfaces OR as a nullable, it will NOT be optimized and will be “boxed”. You CANNOT use it as it’s underlying type. Calls to any of the properties or functions will be inlined to the call site.

Here’s an example of some code I use which I hope you will be able to use as an example to “fix” your “problem” as I think your code could do something similar to mine and could benefit from using inline class

fun Int.getByte(byteIndex: Int): Byte { /* code to get the byte here */ }
fun Int.replaceByte(byteIndex: Int, value: Byte): Int { /* code to replace the byte here */ }

interface HasAlphaChannel {
    val alpha: Int
}

interface RGBColor {
    val red: Int
    val green: Int
    val blue: Int
}

// This will be optimized as an Int when used as an ARGB8 but NOT as ARGB8? RGBColor or HasAlphaChannel.
inline class ARGB8(val channels: Int): RGBColor, HasAlphaChannel {

    constructor(
        alpha: Byte,
        red: Byte,
        green: Byte,
        blue: Byte
    ): this(
        0x00000000
            .setByte(0, alpha)
            .setByte(1, red)
            .setByte(2, green)
            .setByte(3, blue)
    )

    override val alpha: Int get() = channels.getByte(0).toInt()
    override val red: Int get() = channels.getByte(1).toInt()
    override val green: Int get() = channels.getByte(2).toInt()
    override val blue: Int get() = channels.getByte(3).toInt()
}

fun main() {
    val transparentSwamp = ARGB(64, 0xE0, 0x77, 0x77)
}

I’m not sure how much this helps. Yes inline classes are great, but they don’t solve the OPs problem. Fact is that in 3D graphics there are many “primitive” types that can’t just be represented with an inline class (Vec2, Vec3, Matrix, etc). Even color as in your example is not always a good fit since you might want to use more than 1Byte per color channel e.g. for normal maps.
As someone who also working on rendering(hobby project) I personally haven’t found many places where inline classes provide a real performance benefit (that said I haven’t actually benchmarked this). More often they are useful to provide wrapper classes around open-gls many uses of integers to represent different states, “objects”, settings, etc.

I know it is not a perfect solution but it is a work around one of his main issues, which was a lot of objects being allocated on the object heap.

Like you mentioned, the vm itself does a great job at eventually figuring out when to put certain things on the heap vs stack.

Inline class wrapping a primitive gets around this as it does not allocate to the heap nearly as much, only when used in the same way that primitives allocated on to the heap are.The “object” doesn’t actually exist at runtime as it’s abstracted away.

And I know my color solution is not optimal for some situations but I do use it in a small project I am working on (very basic voxel game engine similar to minecraft classic) and it’s perfect for that use, which is what programming is all about, right? It was used merely an example of what op could do with his Vec classes, for example storing 2 Float inside of a Double (or Long).

I did do a performance benchmark in this project of mine when deciding whether or not to use inline classes and the performance benefit wasnt massively lifechanging, only ~3% increase in speed (measured in FPS, max was ~300 with objects, ~310 with inlined class)

Modern JVMs are extremely powerful when it comes to object allocations and garbage collection, but those things are definitely not close to free. See the following presentation: https://www.infoq.com/presentations/jvm-60-memory/

Thanks for another replies. As you say, inline class provide a method to make object on stack. But, I don’t want to make code unnatural. I know that inline class’s purpose is to prevent overhead of wrapper class. so currently inline class not provides a multi-parameter constructor. And this is not good for me, because I want to make classes like Vec2, Vec3, Mat and these have many values and each value must passed by constructor. Moreover this is impossible, since below reasons.

inline class Vec2(val x: Float){ val y=0.0f } // I don't set value of y
inline class Vec2(val x: Float){ var y=0.0f } // var is not allowed for inline class

I want to Kotlin allow inline class for data class. :cry: ( like struct on C# )

That’s sadly not possible right now, due to the limitations of the JVM. The bytecode just doesn’t support something like this. This will probably be changed with Project Valhalla, but this is still super experimental. I’d be surprised if we see this any time soon.

I don’t know why it is impossible. if there is class like below

inline data class Vec2(val x: Double, val y: Double) {
    inline operator fun plus(other: Vec2) = Vec2(other.x + x, other.y + y)
    inline operator fun times(other: Vec2) = Vec2(other.x * x, other.y * y)
    ...
}

and if there is method like bloew…

fun inline inverse(val w: Vec2){ 
    return Vec2(w.x, -w.y)
}

fun action(val u: Vec2){
    val v = Vec2(1.0, 0.0)
    v += u
    val w = inverse(u)
    list.add(w)
    return w + v
}

fun action(val u: Vec2){
    val v = Vec2()
    val w = Vec2(u.x, -u.y) // inline function be inlined
    list.add(w)
    return w + v
}

fun action(val u: Vec2){
    val _0_x = u.x        // non-inline function's parameter
    val _0_y = v.y        // always reference or primitive type
    val v_x = 1.0
    val v_y = 0.0
    val w_x = _0_x
    val w_y = -_0_y
    list.add(Vec2(w_x, w_y))
    _1_x = v_x + w_x
    _1_y = v_y + w_y
    return Vec2(_1_x, _1_y) // non-inline function's return, too.
} 

Like primitive types, is it possible with auto-boxing? why JVM limits this process?

I’m not sure I understand your suggestion. You are still creating objects when adding to the list and when returning from the action function.

The limitation from the JVM side is that a function can return only one result, hence if you want to return 2 integers you’ll need to wrap them in some object.