Memory footprint of QML applications
-
Hi,
I usually develop under Windows. I wrote some smaller applications using Qt widgets before and currently I'm having a closer look on QML applications.
Today I took a quick look on the memory consumption of a small QML application and compared it with a simple widget based applications using QGraphicsView (both Qt 5.0.1). I was surprised about the greediness of the QML application. Sure, I expected the JS engine and GL stuff would cost some megs - but not that much (+28M actually)! This QML application is really small, so I am somewhat scared now and asked myself if QML is ready for use in real-world scenarios.
Now I hope some of you can report about your experiences using QML. Maybe someone has even written an application that actually works and displays largers sets of data. And what did you observe when developing under Linux?
I mean QML -will be- is used on phones nowadays, so excessive memory consumption shouldn't be a concern. It should really not be higher than when using a JVM engine or the like.
Roland
-
When talking about memory usage, it's important to define precisely what you mean. Broadly speaking, you can break the memory usage down into these categories:
- libraries (like QtCore, QtJsBackend, QtGui, QtDeclarative) which will need to be loaded into (shared) memory when your application starts
- the V8 heap (one per isolate, so if you use workerscript / pragma threaded you'll have two of these)
- runtime type data from loaded QML modules / imports
- runtime type data from your application
- runtime instance data from object instantiations
It's important to note that the V8 engine "preallocates" a hefty chunk of memory on initialisation, and manages all objects in its root context on that V8 heap. So, if you were to run a QML application which had a JavaScript function which continually allocated more memory, you wouldn't see dirty memory usage increasing linearly; instead, you would see it increase dramatically in "jumps" as V8 decides that it needs to increase its heap size (usually by doubling, IIRC, although I imagine they do use some clever heuristics to determine when and how much memory to request from the OS via sbrk etc).
A decent amount of effort went into reducing the memory consumption of QML applications during Qt5 development, but there are some overheads associated with the engine which cannot really be avoided at this point in time. And whenever you're dealing with lots of QObjects, you're implying a reasonably large memory footprint, to be honest.
For more information about the way memory is allocated in a QML application, see the section at the bottom of the http://qt-project.org/doc/qt-5.0/qtquick/qtquick-performance.html performance guide.
Cheers,
Chris. -
Hello Chris,
everything you have written is correct. As I have said, I expecteded some megs of additional RAM usage because I understand what is going on with using JS. But almost 50 MB for a do-nothing app seemed quite high to me. Therefore I'm a little bit concerned and I asked for experiences with real-world use.
Currently I see no easy way to determine how much the inclusion of each of the Qt subsystems actually costs in terms of memory use. QML + V8 and GL put 28 MB weight on the scales in my case. Total use of the do-nothing app is much higher than a Java/WPF/Python do-nothing app.
Do you actually know how much memory V8 preallocates? Can I set some configuration parameters concerning memory usage with the JS engine? Does it ever give back memory to the OS?
And as I have only access to some toy QML applications, what were your experiences with bigger applications? Did the memory consumption stay inside acceptable bounds with the tests you seem to have done?
Thanks, Roland
-
Hi,
Yeah, the "initial memory footprint" of the average QML application is very high, I agree. This is mostly due to the fact that it pulls in so many Qt libraries which QtQuick depends on.
Regarding how much memory V8 preallocates, I don't actually remember, unfortunately (for some reason I'm thinking 8 MB but that might be entirely wrong). A quick look at the code should tell you. It does have configuration parameters which can be set to tweak usage (for example, when they build for Android they set a parameter which affects various things, including heap preallocation and the high-watermark usage heuristic) but I don't think we expose that configuration parameter to the Qt build configuration (so you'd have to manually modify a mkspec to do so, I think? Not 100% sure).
In terms of "bigger" applications, the memory consumption depends entirely on the use-case, and is mostly unrelated to QML itself. By which I mean: if you have a bunch of images being displayed, the memory used for the image data usually far outweighs the overhead / memory usage of the QML elements being allocated to display them.
QML shouldn't leak - and when it does it's a serious bug (at least one of which I am aware of still exists in QtQuick1.x, although it was fixed in Qt5 for QtQuick2.x), so over time the memory consumption shouldn't increase an an unbounded fashion.
I believe that the V8 engine does return memory to the operating system but only when it performs a full mark/sweep/compact garbage collection cycle and additionally is able to release a large chunk of a freed region - but my memory of the internals are sketchy, these days, so I may be wrong.
A colleague of mine just pointed out http://tolszak-dev.blogspot.ch/2013/02/simple-qml-vs-efl-comparison.html that blog which considers the memory usage of a simple QML application (using QtQuick1, so there's no V8 involved there), which has some interesting points.
In my own testing and benchmarking, the main overhead of QML that I've seen is due to QObject proliferation - it's definitely worth manually controlling object lifetimes in some situations, and even better if you can avoid creating new QObjects altogether (eg, via dynamic instantiation on demand, etc).
Cheers,
Chris. -
Luckily it is JS and not Java - because then memory consumption would become really ugly. But still - a 50MB overhead per application is nothing to sneeze at, especially on mobile and embedded devices which still come with 1GB of ram or even less - the cheaper Raspberry Pi has only 256 MB ram that is also shared with the GPU.
That is why on several occasions I stated the inclusion of JS is a complete overkill, a full blown JS engine is hardly needed for simple expressions and value bindings. A rudimentary VM would be a better fit, or why not even compiling those to C++ with wrapped in "extern "C"" so expressions can be loaded separately, evaluated and bound to the appropriate function pointers. Not only does this sound a lot more efficient, but considerably easier to implement than integrating a full blown JS engine. Plus there woudln't be the issue of iOS and having to implement yet-another-JS-engine.
But I guess Qt wants to snag some JS developers, most of which aren't known for their love for C++. JS has been heavily promoted the last few years and it is very widely used, even if its OOP design is ugly as hell, at least IMO. But it makes sense - you cannot force a simple scripting language into being a full blown application development language without making it ugly and inefficient.
-
I've seen simple QML eye candy run just fine on a Pi, but I won't go into speculating what would the performance of an actual application be, in a scenario with other background tasks running.
I think that is the reason mobile OS like Android don't really embrace the concept of multitasking - the hardware just isn't capable of running more than one reasonably demanding task at a time. Especially when crippled by lousy Java performance and memory efficiency.
-
The overhead per-application of QML is quite low, as most of the memory usage is shared memory (libs etc) - the "actual" memory overhead is just the JS heap allocated by V8 + a small, fixed overhead caused by the engine. Even the typedata overhead can be minimised if you share your common types (components) in a lib, and preload that lib + the Qt libs in your environment. So, while a single QML application might take 50 MB in ram, two QML applications might take 60 MB (total) in ram, and three QML applications might take 70 MB (total) in ram, and so on.
Really, what you have to be concerned with is things like your graphics chip sharing main ram, and your modem etc. After loading your kernel and all that jazz, them preloading the Qt libs + your QtQuick Components libs, you'll probably be left with something in the range of 80 MB for user-space applications. That is, you'll be able to easily multitask 3 or 4 moderate sized applications, or 6 or 7 extremely simple applications, or one or two applications plus a web browser, depending on the web browser ;-) If that's enough for your use-case, you should be fine.
Qt5 on Raspberry PI works really nicely. It's an amazing board.
Cheers,
Chris. -
I'd rather see a slightly more expensive Pi with slightly better specs, it is amazing how much more performance and memory a few extra $ can buy. Especially ram, which is cheap as chips nowadays. It doesn't make sense to make too cheap of a product, I mean "cheap" in the negative aspect. Extra memory never hurt anyone.
-
As far as I remember there were some discussions back in the days to make V8 (or any other JavaScript environment) optional and beeing able to restrict applications to trivial bindings or at least V4-able expressions only.
Is this idea still on the table?
-
I have this thing in my head where you use QML during development and when you are done everything compiles to platform native binary - bindings and everything, Parent child hierarchies become aggregated classes and allocation is blazing fast stack. But it will require a different set of components, available both in C++ and QML, and public access to the scenegraph (yeah, there is an actual reason I've been (*)itching about this).
-
heh, lots of speculation in this thread, not so much actual data.
As a consultant I work in different projects, and have been 3 QML projects of quite large size. All for embedded. (one linux, one symbian, one wince).
In reality the amount of memory allocated is really not an issue. We have not really ran out of memory due to QML related things.One big possible-misconception I want to address is one of linear growth.
What Roland_R tests (an do-nothing app) is only really useful measurement in a linear-growth application. So if you twice the amount of stuff, you allocate twice the amount of memory.
This principle is not true, and has not been true for years. You run an OS that takes memory, to go back quite some years.Similarly, when you use QML, the base amount of memory (what a do-nothing app uses) is similar to a relatively mature one with many screens and items.
-
Most of the people that posted in this thread are not so simple minded to infer the memory requirements of "big" applications from the amount of memory of a do-nothing app, I guess.
But as the numbers I observed were quite high the question for experiences with somehow heavier real-world applications is valid. Even more valid as most of the applications I could find were toy-like.
So the initial question was directed to people like you that actually have these experiences from their work. So thank you for providing the valuable information that you had experienced no problem with memory consumption in large scale applications.