dtech
dtech

Reputation: 49289

Caching for frequently created from source components

I am in a highly dynamic context, heavily using dynamic instantiation of components from sources. Naturally I am concerned with the overhead from having to parse those sources each and every time an object is dynamically created. When the situation allows it, I am using manual caching:

readonly property var componentCache: new Object
function create(type) {
    var comp = componentCache[type]
    if (comp === undefined) { // "cache miss"
        comp = Qt.createComponent(type)
        if (comp.status !== Component.Ready) {
            console.log("Component creation failed: " + comp.errorString())
            return null
        } else {
            componentCache[type] = comp
        }
    }
    return comp.createObject()
}

Except that this is not always applicable, for example, using a Loader with a component which needs to specify object properties using the setSource(source, properties) function. In this scenario it is not possible to use a manually cached Component as the function only takes an url. The doc does vaguely mention "caching", but it is not exactly clear whether this cache is QML engine wide for the component from that source or more likely - just for that particular Loader.

If the active property is false at the time when this function is called, the given source component will not be loaded but the source and initial properties will be cached. When the loader is made active, an instance of the source component will be created with the initial properties set.

The question is how to deal with this issue, and is it even necessary? Maybe Qt does component from source caching by default? Caching certainly would make sense in terms of avoiding redundant source loading (from disk or worse - network), parsing and component preparation, but its effects will only be prominent in the case of excessive dynamic instantiation, and the "typical" QML dynamic object creation scenarios usually involve a one-time object, in which case the caching would be useless memory overhead. Caching also doesn't make sense in the context of the possibility that the source may change in between the instantiations.

So since I don't have the time to dig through the mess that is the private implementations behind Qt APIs, if I had to guess, I'd say that component from source caching is not likely, but as a mere guess, it may as well be wrong.

Upvotes: 0

Views: 1173

Answers (2)

spring
spring

Reputation: 18487

Not an answer per se, I tripped into the question of component caching yesterday – and was surprised to discover that Qt appears to cache components. At least in creating dynamic components, the log statements related to createComponent only appear once in my test app. I've searched around and haven't seen any specific info in the docs about caching. I did come across a couple of interesting methods in the QQMLEngine Class. Then I came across the release notes for Qt 5.4

The component returned by Qt.createComponent() is no longer parented to the engine. Be sure to hold a reference, or provide a parent.

So? If a parent is provided, it is cached (?) That appears to be the case. (and for 5.5+ ?) If you want to manage it yourself, don't provide a parent and retain the reference. (?)


QQmlEngine Class

QQmlEngine::clearComponentCache()

Clears the engine's internal component cache.

This function causes the property metadata of all components previously loaded by the engine to be destroyed. All previously loaded components and the property bindings for all extant objects created from those components will cease to function.

This function returns the engine to a state where it does not contain any loaded component data. This may be useful in order to reload a smaller subset of the previous component set, or to load a new version of a previously loaded component.

Once the component cache has been cleared, components must be loaded before any new objects can be created.


void QQmlEngine::trimComponentCache()

Trims the engine's internal component cache.

This function causes the property metadata of any loaded components which are not currently in use to be destroyed.

A component is considered to be in use if there are any extant instances of the component itself, any instances of other components that use the component, or any objects instantiated by any of those components.

Upvotes: 1

dtech
dtech

Reputation: 49289

After some toying with the code, it looks like caching also takes place in the "problematic case" of Loader.setSource().

Running the example code from this question, I found out that regular component creation fails to expand a tree deeper than 10 nodes, because of Qt's hard-coded limit:

// Do not create infinite recursion in object creation
static const int maxCreationDepth = 10;

This causes component instantiation to abort if there are more than nested 10 component instantiations in a regular scenario, product incorrect tree and generating a warning.

This doesn't happen when setSource() is used, the obvious reason for this would be that the component is cached and thus no component instantiation takes place.

Upvotes: 0

Related Questions