Is there some comprehensive GC guidelines available?

Hi, cocos community.

I have been playing unity for quite a while and just come to cocos creator recently. I played with the typescript API and got some questions on GC, I want to hear some opinions and advice from experienced devs here.

  1. “GC spike” has been an important performance concern in unity, so pooling is using extensively to tackle that, and it’s recommended to reduce GC alloc as much as possible. How is cocos doing with GC? Do you guys often see GC impacting your performance?

  2. I’ve noticed that the Vec3 and Quat seem to be reference type instead of value types, so it means new instances will cause gc_alloc, right? You might need quite a lot of temp Vec3/Quat in update, do you just declare them as member variables?

  3. Is there some comprehensive performance guidelines to help us avoid potential performance issues?

  1. Cocos Creator engine typically relies on the JavaScript engine of the browser running on the Web platform to manage GC behavior. Most modern browsers use the V8 engine, which automatically performs GC and memory release.

  2. You are correct that creating new instances increases reference counts. Therefore, we typically avoid creating new instances frequently. We may consider accessing global properties or using a cache pool to recycle instances. The Cocos Creator engine also takes advantage of this for performance optimization. https://docs.cocos.com/creator/manual/en/advanced-topics/jsb-optimizations.html

  3. In addition to some conventional TS programming optimization methods, Cocos Creator engine provides the NodePool to optimize performance and reduce GC Cocos Creator 2.4 Manual - Pooling

  4. Currently, we do not have a comprehensive performance guide. If you encounter performance issues, you can post them anytime and we will reply to you as soon as possible.

Hi, thanks for reply.

I’m not quite familiar with ts/js bindings, so the jsb optimization section kind of confuses me. Are you suggesting we should write some C++ plugins for performance critical code? But I saw somewhere in manual that we can only write plugins with js?

As for the properties, I checked the source code of properties of forward/right/up of Node class, it seems that they would create a new instance of Vec3 for every call, so should we avoid using them too?

I found the NodePool but not some generic pool for Vec3/Quat, does that mean we are suggested to write our own pool for that?

I’ve also found that Vec/Quat/Rect/etc extends the ValueType, this “ValueType” doesn’t mean the same “value type” in C#, right?

EDIT:

Found the generic pool class;

I’m not quite familiar with ts/js bindings, so the jsb optimization section kind of confuses me. Are you suggesting we should write some C++ plugins for performance critical code? But I saw somewhere in manual that we can only write plugins with js?

I think you can just write codes in c++ and bind it to js for performance sensitive codes.

As for the properties, I checked the source code of properties of forward/right/up of Node class, it seems that they would create a new instance of Vec3 for every call, so should we avoid using them too?

I am not sure what codes create Vec3 every call. In general, we should reuse object as possible. In Typescript, you can create a file scope object, and reuse it for all the codes in the file, for example

Vec3 tmpVec3 = new Vec3();

class A {
    public func() { 
        // use tmpVec3 here
    }
}

class B {
    public func() {
        // use tmpVec3 here
    }
}

I found the NodePool but not some generic pool for Vec3/Quat, does that mean we are suggested to write our own pool for that?

Cocos provides a Pool class. You can refer to Cocos Creator API for detail information.

I’ve also found that Vec/Quat/Rect/etc extends the ValueType , this “ValueType” doesn’t mean the same “value type” in C#, right?

I think it is different. It is just a common class that defines some interfaces. Though i think it is not a good name.

1 Like

Node.forward / right / up, they seem to create a new Vec3 instance every call.

get forward (): Vec3 {
        return Vec3.transformQuat(new Vec3(), Vec3.FORWARD, this.worldRotation);
}

Yep, a new Vec3 is created every call. As this function is not invoke frequently. If it affect the performance, the we may use a global Vec3 to hold a value and return a readonly Vec3 object. Then the invoker should duplicate it if it wants to modify the value.