When you have a TextBuffer, and do something like:
buffer.insert(iter, "Hello World");
this causes TextBuffer.InsertText to be emitted (as this is where GTK
actually carries out the textual insertion, as it happens).
if you've meanwhile connected to that signal, ie
buffer.connect(new TextBuffer.InsertText() {
public void onInsertText(TextBuffer source, TreeIter where, String text) {
// ...
}
});
the text String you get will, of course, have the same "Hello World"
content, but it will be a different String object [since it is created
with NewStringUTF() in bindings_java_signal.c as the signal emission is
marshalled and and the GClosure invoked]. This is fine.
Except that it's a bit wasteful to have our JNI layer to have to create
a new String when we know full well that a String with equivalent data
already exists. And worse, that we *just* passed such a String across to
the JNI layer where the char[] was converted (copied) into a UTF-8
gchar*.
So while everyone knows that two Strings have to be checked by equals()
rather than by reference ==, the whole point of Strings is that they are
immutable and reusable.
The number of arraycopy() that happens on char[] in the Sun Java library
to preserve the immutable String character is already staggering and a
common hot spot in profiling.
So I'm wondering if we couldn't connive to at least not make it worse.
If we convey the same String to a signal handler as was passed in by the
initiating method, we could save a lot of copying.
The thought I had was to keep a tiny (last 8 or so, though even last 1
would do) cache of gchar* to jstring mappings when we pass Strings
across to JNI. Then during signal emission we could check the last 1 (or
8 or whatever) mappings to see if we've already got a String for that
gchar* there, and if so just return it rather than creating a new one.
Weak references, of course.
It might seem minor, but right now I'm doing a lot of "insert huge block
of text into a TextView, then ignore the InsertText signal because I
know I just inserted it programmatically" .... but I have to ignore the
signal _in_ the handler, and that's after the String copy has been
created for the parameter. So I'm creating lots of Strings that are
being ignored and rapidly thrown away.
And while this falls squarely into the "premature optimization" category
(the app is responsive), it's the sort of thing you like not to do if
you can help it.
Anyway, String reuse in general is an issue I'm thinking about. A
variation on the theme is the possibility of using Direct ByteBuffers
created JNI side and a view to a wrap piece of a native gchar*, rather
than copying the thing into a String all the time with JNI
NewStringUTF(). That would be wizard, except that we can't subclass or
replace java.lang.String. So I'm not sure what good it would actually do
given all our API is String, naturally.
Discussion welcome.
AfC
Sydney
--
Andrew Frederick Cowie
Operational Dynamics is an operations and engineering consultancy
focusing on IT strategy, organizational architecture, systems
review, and effective procedures for change management: enabling
successful deployment of mission critical information technology in
enterprises, worldwide.
http://www.operationaldynamics.com/
Sydney New York Toronto London
|