Strange Lag of QML Garbage Collection
-
My game logic is written in JavaScript of QML, and drawing image api is realized in C++:
Q_INVOKABLE void drawImage(ColorImage* img,qreal x,qreal y);The strange problem is if I create a big JS object:
@
var gRes = {};
for(var i =0;i<100;i++){
var tmp= {};
for(var j=0;j<400;j++){
tmp[j] = function(){};} __gRes__[i] = tmp; } __gRes__={};@
The phenomenon is my game lag periodically,even __gRes is reset to '{}' in the end, as above.
I profiled and found that: every lag is caused by garbage collection.
But my big object is created only for one time. The periodical lag can not be explained.I do not know the garbage collect mechanism of QML. My Qt version is 5.3.
Does anyone encounter such problem or do such test?
-
What is your drawImage function doing? Is it using OpenGL directly, adding something to a scene or using QPainter?
I'm not sure what the point of your loop is. You are creating 100 objects and assigning those objects 400 empty functions each. Then discarding it. Is this run every frame?
In general, I would go for creating the majority of objects at the start of the level and keep them for the duration of that level. Object allocation and GC shouldn't have to happen that often while the game is running.
-
[quote author="sletta" date="1413180722"]What is your drawImage function doing? Is it using OpenGL directly, adding something to a scene or using QPainter?
I'm not sure what the point of your loop is. You are creating 100 objects and assigning those objects 400 empty functions each. Then discarding it. Is this run every frame?
In general, I would go for creating the majority of objects at the start of the level and keep them for the duration of that level. Object allocation and GC shouldn't have to happen that often while the game is running.
[/quote]my drawImage simply draw QImage with QPainter.
yes, as you mentioned, all my sprites are created in advance and reuse, and simply drop from top to bottom, and loop. During my logic, no new big object is created.My logic seems like this:
@function loop(){
self.sceneUpdate(now,dt);
self.myDraw();
}@Everything is fine if I don't create big temp object only one time like this:
@var gRes = {};
for(var i =0;i<40000;i++){
tmp[j] = {};
}
gRes={};@And the big object "gRes" has no relation with anything else.
My test environment is Iphone4, ios6.1, Iphone4s ios7.1.
I think it is because of the gc mechanism of js engine.Big object created cause the mark-sweep gc's sweep is slow.
-
Creating 40000 objects is going to put a bit of strain on the GC for sure. Each {} is a new object after all. You could try filing a bug about that on bugreports.qt-project.org, but it is quite a few to allocate per frame. For a game, I would rather aim for pre allocation of the most used objects on a per-level basis and then try to keep temporary objects per frame to a minimum, like less than 10 :)
For the graphics side, you should consider using Image elements in QML rather than QImage and QPainter. QImage is a software side image. QPainter opened on a GL FramebufferObject will need to upload those images and will suffer from limited draw call count (see "Number of Draw Calls" in http://www.sletta.org/apps/blog/show/42708211-looking-at-throughput-in-qt-quick). If the QPainter is opened on an QImage or QPixmap, you will be doing the rasterization of the sprites in software and then doing a full texture upload of the rendered frame, which then needs to be drawn using GL. Either way, it is not optimal, and will eat out of the performance budget and may be a contributing factor to the lags in caused by the GC.
Good luck with the game :)
-
Thanks, sletta.
GC is a problem of javascript. After several days' test , I think the QML javascript engine does not perform well in this situation.
I use JavaScriptCore to test the same code and it perform a little better.
Hope to improve in next qt version. :-)