I'm a contributor to Ardor3D where jdom is used for handling a certain format of 3D models (Collada).
Recently I upgraded it from jdom 1.x to 2.x and today another contributor (@ricardolpd) noticed a big perfomance impact when loading one of his 4meg (xml) models. The slowdown happens when calling SAXBuilder.build(..).
I profiled everything using VisualVM and found the problem in org.jdom2.input.sax.TextBuffer. First, some numbers obtained with simple System.currentTimeMillis() benchmarking of SAXBuilder.build(..):
jdom1: ~270ms
jdom2: ~46000ms
In jdom2, 60% of the time (which was the top hotspot when profiling) was spent in org.jdom2.internal.ArrayCopy.copyOf(). This method is used in TextBuffer.append(). In jdom1, the underlying array of the text buffer was resized using the following method:
private void ensureCapacity(int csize) {
int capacity = array.length;
if (csize > capacity) {
char[] old = array;
int nsize = capacity;
while (csize > nsize) {
nsize += (capacity/2);
}
array = new char[nsize];
System.arraycopy(old, 0, array, 0, arraySize);
}
}
which was called in TextBuffer.append(char[] source, int start, int count) as ensureCapacity(arraySize + count);.
In jdom2, the array is resized directly in the append method by:
if ((count + arraySize) > array.length) {
array = ArrayCopy.copyOf(array, count + arraySize);
}
Can you spot the difference? In jdom2, the array is resized to exactly the requested size. In jdom1, it is resized with an additional amount of extra space (nsize += (capacity/2);). As the extra buffer space is missing now, it causes severely more array copies than in jdom1 and therefore having an impact on performance, in case where the xml consists of much character data.
My suggestion is to revert to the resizing behavior of jdom1. Is something speaking against that?
Also, the class javadoc of TextBuffer isn't current anymore. It is still related to the jdom1 version where a prefixString was used.
I'm a contributor to Ardor3D where jdom is used for handling a certain format of 3D models (Collada).
Recently I upgraded it from jdom 1.x to 2.x and today another contributor (@ricardolpd) noticed a big perfomance impact when loading one of his 4meg (xml) models. The slowdown happens when calling
SAXBuilder.build(..).I profiled everything using VisualVM and found the problem in
org.jdom2.input.sax.TextBuffer. First, some numbers obtained with simpleSystem.currentTimeMillis()benchmarking ofSAXBuilder.build(..):jdom1: ~270ms
jdom2: ~46000ms
In jdom2, 60% of the time (which was the top hotspot when profiling) was spent in
org.jdom2.internal.ArrayCopy.copyOf(). This method is used inTextBuffer.append(). In jdom1, the underlying array of the text buffer was resized using the following method:which was called in
TextBuffer.append(char[] source, int start, int count)asensureCapacity(arraySize + count);.In jdom2, the array is resized directly in the
appendmethod by:Can you spot the difference? In jdom2, the array is resized to exactly the requested size. In jdom1, it is resized with an additional amount of extra space (
nsize += (capacity/2);). As the extra buffer space is missing now, it causes severely more array copies than in jdom1 and therefore having an impact on performance, in case where the xml consists of much character data.My suggestion is to revert to the resizing behavior of jdom1. Is something speaking against that?
Also, the class javadoc of TextBuffer isn't current anymore. It is still related to the jdom1 version where a prefixString was used.