When looking at QtQuick & QML performance, my key rule is generally to do is to do as little as possible. Don't create items and bindings that you don't necessarily need right now to show to the user.
I can't give you an exact number (because after all, there really isn't one - it's project and hardware dependent), but I would suggest that QtQuick is best suited to displaying a number in the single digit thousands of items at a time on screen. More than that, and things are going to start to get a little rough on resource usage and performance.
QML, for better or worse, is a very easy language to hide costs in by being very expressive. When working in it, you need to consider what happens under the hood when writing this code; each Item you create is a QQuickItem subclass that gets allocated, and each property you set is a C++ function call. For bindings, the JavaScript engine needs to evaluate that binding (evaluating other things it depends on, too), before it even makes that function call to set the property value.
Looking at your Flickable snippet, you have a Repeater of columns containing a Repeater of rows. You say that you allow up to 150x150 grid. Let's do some rough math on that number. For each tile, you have (at least) two Rectangles, an Image and a Text item, giving a total of 4 items per Tile.qml instance. In addition, you have a fixed cost of a Row and a Repeater for each.
This means that the total creation cost of a single row on your grid is:
2 + (4 * mapSize) items, giving you a total of 602 items per row. Then, you have that, multiplied by 150, giving you a total cost of 90,300 items to create that grid.
Each row has a number of bindings, too: I count 9 in tile (7 in Tile itself, excluding the "id" assignments which are a bit special, plus the two x & y coords), plus another two for the Row and Repeater bindings, that's 2 + (9 * mapSize) bindings per row -- 1352 bindings per row, 202,800 bindings for the whole grid.
All in all, this is a very large number of items and bindings to be using at a single time.
Each of these items has significant costs under the hood - for example, a hundred bytes here and there for each item itself, extra allocations for the bindings you create on each of them, allocations for the QSGNode instances the items create to actually get something on screen, and using a Repeater also means that you have a few extra allocations on the JavaScript heap for each delegate... It all can add up to a very large amount of memory, depending on how many things you are creating at once.
So, to directly answer your question, the simple answer is "don't create so much stuff". I'm not sure how you can achieve that, but here's a few possibilities:
- You could incorporate more of the individual Tile into the Image for it, e.g. the Rectangles, and just have something like
Image { Text { anchors.centerIn: parent } } as your tile
- You could consider whether you could make use of
GridView somehow to help you with this, but it's going to provide some constraints on your design.
- If GridView does not suit your needs, I would suggest that a good step is write some kind of view item, responsible for creating and positioning Tile instances, such that you are only instantiating tiles for the part of the map that is being shown at any given point.
For the last option, it'd go something like this. You'd look into subclassing QQuickItem (on the C++ side), and have a Q_PROPERTY(QQmlComponent* tileDelegate READ tileDelegate WRITE setTileDelegate NOTIFY tileDelegateChanged). In the setTileDelegate setter, call QQuickItem::polish, and then, override QQuickItem::updatePolish and there, create (or just reposition) instances of the provided tileDelegate component, offset from the currently displayed position on screen, until your "GameViewThing" was completely covered with tiles again.
I'm a little vague here – sorry for that – but a full example would be quite a bit of code, so I hope I've given enough information & direction for you to be able to start out on your own.