If you are a java developer who’s using Apache Axis for developing web service client applications/mashups and facing “Out of Memory” issues because of “org.apache.axis.message.MessageElement”, then this post can help you in fixing this memory error. This post if also of relevance to developers creating application using Salesforce Web Services via Axis client stubs, its quite easy to go Out of memory when using salesforce partner wsdl to create a bunch of records.
“MessageElement” a nasty, badly documented class !
This class is the one that most of the developers use or even its used by Axis under the hoods at a couple of places. The sad part about this class is its very badly documented and the way developer needs to keep its state correct is not clear at all. Over that, this class eats insane amount of memory if used for bulk operations. So developers should be very careful to operate not in bulk, but chunks with this class.
Using MessageElement class in a risky way
MesageElement class mostly becomes memory hog when creating new instances of it. I faced out of memory issues for this class during one of my recent assignments, we were trying to create many records in salesforce and operation failed always because of out of memory error. We were using the salesforce sample code to create MessageElement instances like this below
public static MessageElement newMessageElement(String name, Object value) throws Exception {
MessageElement me = new MessageElement("", name);
me.setObjectValue(value);
Element e = me.getAsDOM();
e.removeAttribute("xsi:type");
e.removeAttribute("xmlns:ns1");
e.removeAttribute("xmlns:xsd");
e.removeAttribute("xmlns:xsi");
me = new MessageElement(e);
return me;
}
This is a strange but was working way for us to get the job done, we are not Axis experts unfortunately 😉
But this stuff become unusable then we tried to research around possible solutions, so ideas that came out during that research was
To create a single message element and clone it rather creating from scratch.
This didn’t worked, MessageElement maintains a complex XML structure that is not easily to clone and then transform to new values.
To reduce the number of records we are working on, call Garbage collector and sleep 🙂
Finally one of my peer Amit, figured a way that is similar to cloning MessageElement, but not really a clone and it worked for us. He suggested to cache a Template MessageElement, and use that for creating new MessageElements. Its explained in detail below.
Alternate Solution – A Template Element
Alternate solution was to cache the Xml “org.w3c.dom.Element” used internally by MessageElement class. MessageElement also gives constructors that accept org.w3c.dom.Element. So we can cache a single Element instance as Template to create new MessageElement instances. As shown below.
private static MessageElement TEMPLATE_MESSAGE_ELEMENT = new MessageElement(
"", "temp");
// The Template org.w3c.dom.Element instance
private static Element TEMPLATE_XML_ELEMENT;
static {
try {
// Create and cache this org.w3c.dom.Element instance for once here.
TEMPLATE_XML_ELEMENT = TEMPLATE_MESSAGE_ELEMENT.getAsDOM();
} catch (Exception e) {
throw new RunTimeException(e);
}
TEMPLATE_XML_ELEMENT.removeAttribute("xsi:type");
TEMPLATE_XML_ELEMENT.removeAttribute("xmlns:ns1");
TEMPLATE_XML_ELEMENT.removeAttribute("xmlns:xsd");
TEMPLATE_XML_ELEMENT.removeAttribute("xmlns:xsi");
}
public static MessageElement fromTemplateElement(String name, Object value)
throws SOAPException {
// Use the TEMPLATE org.w3c.dom.Element to create new Message Elements
MessageElement me = new MessageElement(TEMPLATE_XML_ELEMENT);
me.setObjectValue(value);
me.setName(name);
return me;
}
So when we started using the new fromTemplateElement() method, we never got OutOfMemory error, even for big operations that involve handling too many records.
Benchmarks – Why alternate solution “Template Element” is really better ?
For benchmarking I just setup a simple fixture, that you guys can also try quickly to get confidence. In this fixture I just iterated a 100,000 times to create 100,000 MessageElement instances using both approaches.
Here is the fixture (My Machine Core2Duo, 4 Gigs of RAM)
public class MessageElementTest {
// NOTE: Copy the above code and static block for both methods here
public static void main(String[] args) throws SOAPException {
List<MessageElement> elems = new ArrayList<MessageElement>();
for (int i = 0; i < 100000; i++) {
// Create fake name using current millis
String name = "name" + System.currentTimeMillis();
Object value = "val" + System.currentTimeMillis();
// Print iteration and free memory
System.out.println("Iteration " + i + " Free Memory :"
+ +Runtime.getRuntime().freeMemory());
// First approach
MessageElement e = newMessageElement(name, value);
elems.add(e);
}
System.out.println(elems.size());
}
Here are the results, this approach never completed 100,000 iterations and failed near 35,000. Here is the sample output
Iteration 0 Free Memory :15874400
Iteration 1 Free Memory :14616912
.......
.........
.......
Iteration 35642 Free Memory :5256
Iteration 35643 Free Memory :1344
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
Now to try alternate approach just comment the single line and add this line as shown below
// First approach
// MessageElement e = newMessageElement(name, value);
// Alternate Approach
MessageElement e = fromTemplateElement(name, value);
Now I was able to complete all 100,000 iterations without any Out of memory issues etc. Even I ended with decent memory in hand. Here are the results
Iteration 0 Free Memory :15874400
Iteration 1 Free Memory :14252944
Iteration 2 Free Memory :14252944
...
....
....
Iteration 99998 Free Memory :17744408
Iteration 99999 Free Memory :17744408
100000
So its clearly visible that the original approach is just good for sample codes, if you are planning to put your app in production then must try the Alternative approach.
All the best !
Comments (3)
Anonymoussays:
July 1, 2010 at 2:40 pmThis is really great. I want to give a Grand Salute to you.
Anonymoussays:
July 6, 2010 at 2:32 pmThanks @kanes !
Anonymoussays:
August 31, 2010 at 12:50 pmThanks. Really made my life colorfull