To put it crudely:
The amount of memory available to a python application can grow
during its lifetime, but it can never fully shrink back to where it
started.
There is no way to force python to release unused memory back to the system.
So the best you can do is try to manage the amount by which the memory grows. One obvious way to do this is to delete unneeded objects, so that newly created objects can re-use the memory that has already been allocated.
But what if the application seems unable to re-use the memory? This either means that objects are not being deleted cleanly (i.e. there are references to them being kept somewhere), or, much less likely, that there is an underlying memory leak in PyQt/Qt.
Tracking down extra references kept to objects can sometimes be quite tricky (to say the least). Some common "hiding places" in PyQt are signals connected using lambda (or functools.partial), or monkey-patched protected methods. But there are no hard-and-fast rules for finding them.
As it stands, the example code in the question does not seem to have any places where extra references could be "hiding". So if the memory usage goes up "every time" a tab is created (as the OP claims), then the problems must lie elsewhere in the application - or to be more precise, the problems probably lie in how the objects are created, rather than in how they are deleted.