PDF Viewing Support (poppler-qt4)
Eskil Abrahamsen Blomfeldt
eblomfel at trolltech.com
Fri Feb 15 14:55:47 CET 2008
Adam Batkin wrote:
> The interesting bit is the typesystem file for the PdfDocument class:
>
> <object-type name="PdfDocument">
> <modify-function signature="page(int)const"
> access="private" rename="page_helper">
> <modify-argument index="return">
> <reference-count action="ignore"/>
> <define-ownership class="java"
> owner="java"/>
Is the PdfPage a QObject? If not, then you should be careful doing this.
The reason is that if Java has the ownership of a C++ object, the C++
object will be destroyed along with the Java object when the GC sees
fit. This of course means that you should make sure you have no dangling
references to the C++ object on the C++ side.
The other caveat is that if the class is not a QObject, then special
rules apply. Since we do not control the C++ object's destructor, we
have no control over when C++ object is destroyed. Therefore we cannot
reuse the Java objects we automatically create to map the C++ objects.
I.e. here's the danger I see:
1. User calls Java version of page()
2. This in turn invokes the generated JNI-based code to convert the
PdfPage pointer to a Java object.
3. Conversion code creates a Java object bound to the C++ object with
ownership of the C++ object. (the conversion code *always* creates a new
Java object, since there is no way of detecting whether the PdfPage
pointer has been mapped before.)
4. User calls page() again, with the same index as before.
5. C++ returns the same PdfPage pointer because we requested the same page.
6. Conversion code creates a second Java object bound to the same C++
object, and this also has ownership of the C++ object.
7. One of the two Java objects goes out of scope and GC kills it.
8. The Java object owns the C++ object, so the finalizer destroys the
C++ object
9. The second Java object is still alive and tries to access the
now-invalid data.
If this is the case, you should be able to crash pretty easily by
calling e.g. page(0) a bunch of times, only retaining the last
reference, and then trying to call a method on this.
If PdfPage is a subclass of QObject, then other rules apply, because we
can track the destruction of QObjects, so you should only get a single
Java object per C++ object, and the code above should work, I think. The
default ownership in that case is that C++ owns both its own object and
the Java object and is not garbage collected.
Again, this should be easy to test. You should also be able to check
that you are in fact getting the same Java object with each call to
page() for a specific index by checking that the identity of the two
objects in Java are equal (if (object1 == object2) ...)
>
> I did some testing with a giant List of every PdfPage ever obtained,
> and made sure that no PdfDocuments were ever garbage collected
> (without the <modify-argument bits the PdfDocuments would often be
> GCed too early).
I'm not sure why this would happen, though. The default behavior is that
the return value of page() has what we call "split ownership" which
means that Java is allowed to garbage collect the Java object, but C++
owns the C++ object so this will live until it's deleted.
If they are QObjects, then the Java objects of the PdfPage objects
should not be garbage collected until the corresponding C++ object is
deleted. The PdfDocument object, granted it's created in Java, should
live as long as there are references to it, which should be guaranteed
by the reference set in the PdfPage object.
So, as far as I can see: as long as you have a reference to the PdfPage
object, this has a reference to the PdfDocument object, the PdfDocument
object should remain in memory. How did you confirm its deletion?
It might be that something in this analysis is wrong, though, since it's
all from the top of my head, but you might want to keep alert to this
having consequences further down the road in case I am right. :-)
Very cool project, by the way. I wish you the best of luck and will help
as much as I can with any questions you have.
-- Eskil
More information about the Qt-jambi-interest
mailing list