[Kde-bindings] A sample of our subset of QtC
Richard Dale
Richard_Dale at tipitina.demon.co.uk
Sat Jan 11 13:17:16 UTC 2003
On Saturday 11 January 2003 12:03 pm, Joseph Wenninger wrote:
> For .Net/Mono/pnet you have to track both, the managed and the reall c++
> object to be able to handle repartending of widgets (eg
> QWidget::reparent) and derived classes correctly, without risking that
> one of them gets deleted by the garbage collector, that's what Adam
> tries to do with the managedObject void* pointer. It makes things easier
I'm having trouble following the C# talk about garbage collection issues
because the CLI has its own terms for things.
Anyway, heres how the QtJava memory management works, and why I don't have a
problem with re-parenting widgets:
Each java instance, wrapping a Qt C++ instance has two instance variables;
'long _qt' and 'boolean _allocatedInJavaWorld'. '_qt' holds the a pointer to
the C++ instance (0 if there isn't one yet, or if it's been deleted).
For example:
public class QFont implements QtSupport {
private long _qt;
private boolean _allocatedInJavaWorld = true;
...
'_allocatedInJavaWorld' is true if the java instance was created via a java
new statement. But if a C++ instance has been returned from a Qt method which
doesn't already have a corresponding java instance, the java wrapper instance
is created and '_allocatedInJavaWorld' is false. Then the java runtime won't
attempt to delete the C++ instance at garbage collection time - that's up to
the C++ code which created it.
This hash table is used to keep a mapping between a given C++ instance, and
the corresponding java wrapper (the key is the address of the C++ instance as
a hex string):
/** Uses a C++ key to retrieve the corresponding Java instance */
public static WeakValueMap qtKeyToJavaMap = null;
When a java instance is garbage collected, it automatically drops out of this
map (the value is a weak reference which doesn't prevent garbage collection
happening).
Each java class has these three methods - dispose(), isDisposed() and
finalize(). Normally, finalize() is called by the java garbage collection
runtime and the C++ instance is deleted.
The dispose() method can be called to delete the C++ instance ahead of garbage
collection, and then isDisposed() will be true. This is useful when you have
allocated a large number of large objects like QPixmaps and you've finished
with them - on windows you're only allowed a finite number of pixmap
resources.
In the finalize() methods for classes which are descendents and QWidget code
like this is generated:
JNIEXPORT void JNICALL
Java_org_kde_qt_QScrollBar_finalize(JNIEnv *env, jobject obj)
{
if ( QtSupport::allocatedInJavaWorld(env, obj)
&& ((QScrollBar*)QtSupport::getQt(env, obj))->parentWidget(TRUE)
== (QWidget *) 0) {
delete (QScrollBar*)QtSupport::getQt(env, obj);
QtSupport::setQt(env, obj, 0);
}
return;
}
A similar test is generated in the finalize() methods that are only
descendents of QObject, and not QWidgets.
The underlying C++ instance is deleted iff it was allocated via a java new
statement, and it doesn't have any parent widgets. So a java instance can be
garbage collected, and still not delete its C++ instance.
Some Qt classes which are not descendents of QObject still need custum
finalize() code to look for 'parents'. Or the test needs special
customization, for example, QListViewItem needs this test:
JNIEXPORT void JNICALL
Java_org_kde_qt_QListViewItem_finalize(JNIEnv *env, jobject obj)
{
if ( QtSupport::allocatedInJavaWorld(env, obj)
&& ((QListViewItem*)QtSupport::getQt(env, obj))->parent() == 0
&& ((QListViewItem*)QtSupport::getQt(env, obj))->listView() == 0 )
{
delete (QListViewItem*)QtSupport::getQt(env, obj);
QtSupport::setQt(env, obj, 0);
}
return;
}
When a C++ Qt parent instance is deleted, it deletes all it's children which
may include instances with java wrappers. I added callbacks in the delete()
mehthods of *JBridge classes like this:
~QListViewItemJBridge() {QtSupport::qtKeyDeleted(this);
The qtKeyDeleted() method sets '_allocatedInJavaWorld' to false, so these
child instances aren't deleted twice when their finalize() methods are
called.
So that's my 'theory of Qt object tree/garbage collection coordination' as
used in the java bindings.
-- Richard
More information about the Kde-bindings
mailing list