I've got a straight forward app that creates a bunch of XML (about 5K's worth) with JDOM, posts it to a servlet, then gets about the same amount back. After my app does this about 7000 times, it gets a stack overflow. I've run it inside optimizeit to see what is happening, but I still don't really know why it crashes. Below is the console output when it crashes. Any interesting note is that it seems that the "heap" space, and "heap in use" as reported by optimizeit grows steadily. It starts at about 25meg/35meg, and when it crashes, it is at about 58Meg/60Meg. Even after the crash, when I pull up task manager (win2k) it shows only one jave.exe running (1.3) and that is taking 164,016K Ram. (I'm still now swapping)
Any clues on the steps I might take to solve this problem would be appreciated.
-Peter Kellner java.lang.OutOfMemoryError: at com.mysql.jdbc.Buffer.getBytes(Unknown Source) at com.mysql.jdbc.Buffer.readLenByteArray(Unknown Source) at com.mysql.jdbc.MysqlIO.nextRow(Unknown Source) at com.mysql.jdbc.MysqlIO.getResultSet(Unknown Source) at com.mysql.jdbc.MysqlIO.sqlQueryDirect(Unknown Source) at com.mysql.jdbc.MysqlIO.sqlQuery(Unknown Source) at com.mysql.jdbc.Connection.execSQL(Unknown Source) at com.mysql.jdbc.Connection.execSQL(Unknown Source) at com.mysql.jdbc.Statement.executeQuery(Unknown Source) at com.mysql.jdbc.jdbc2.Statement.executeQuery(Unknown Source) at ProcessUpdateBuffer.insertMysql(ProcessUpdateBuffer.java:437) at ProcessUpdateBuffer.UpdatePatientData(ProcessUpdateBuffer.java:407) at ProcessUpdateBuffer.processUpdates(ProcessUpdateBuffer.java:309) at ProcessUpdateBuffer.updateAddress(ProcessUpdateBuffer.java:93) at QueryTableModel.processAddressCorrection(QueryTableModel.java:151) at AddressCorrectionApp$ProcessAddressCorrection.<init>(AddressCorrectio nAp p.java:388) at AddressCorrectionApp$2.construct(AddressCorrectionApp.java:331) at SwingWorker$2.run(SwingWorker.java:118) at java.lang.Thread.run(Thread.java:479)
This is a known problem with JDOM that can be solve by spending more time on your bicycle.
Is it a stack overflow or an out of memory error? You say stack overflow in your text, but show the stack trace of an OutOfMemoryError. I've only seen a stack overflow error the couple of times I've accidentally coded up an infinitely recursive method call.
Today, I did not feel so well (soar throat) so I stayed off the bicycle. That was probably the problem.
But, I have seen stack overflow, just not this time. I have never actually coded anything recursive (on purpose or outside of class) so I don't think that is the problem. I am a little baffled how the JVM keeps growing.
On second reading it looks like you are running out of memory instead of getting a stack overflow. How big are your documents? Are you letting go of the old document trees before creating, sending, and retreiving the new ones?
Hmm. interesting. I read the experts exchange and got that they don't really like JDOM too much. I'd rather not increase memory because this app needs to run on peoples computers with smaller memory. (like 128MB or so, not my 512MB computer).
I've slashed my code that creates the XML down using JDOM and I'm posting that here. (slahed to make it more readable) The code that is here is actually the end result of a "output buffer" I wrote to control the number of "records" stuffed into each XML. I can set that number to limit the size of my XML files. I've currently had it at "25" records which yields relatively small XML files (maybe 20K most).
Here is the creating XML code. I'm posting separately the stuff that pulls it apart. Since this chunk of code gets executed repeatedly, I'm wondering if there is something special I would need to do do release resources? I don't explicitly mention a "Document" class I don't think.
// Create the root element Element recordSetElement = new Element("RecordSet");
and, as promised, here is the code that takes the response XML doc and pulls it apart. Someplace it seems that memory is getting absorbed and not put back.
SAXBuilder builder = new SAXBuilder(false);
org.jdom.Document doc = null; StringReader sr = new StringReader(xmlString); doc = builder.build(sr);
Element root = doc.getRootElement(); List nestedElements = root.getChildren();
// This is running through records like: RecordSet;CustomerId;Record for (Iterator iterator = nestedElements.iterator(); iterator.hasNext();) { Element o = (Element) iterator.next(); if (o.getName().equals("Record") == true) {
// We are running through the return record, getting out of it what we need List nestedElements1 = o.getChildren(); // First, get CustRecNo out of Record String custRecNum = new String(""); // This is going through the details of the Record. like: ErrorString,FullName,CustRecNo,etc.
for (Iterator iterator1 = nestedElements1.iterator(); iterator1.hasNext();) { Element o1 = (Element) iterator1.next(); if (o1.getName().equals("CustRecNo") == true) { custRecNum = o1.getTextTrim(); } }
// now, localize which patientrecordvector we need to update PatientData tempPatientData = new PatientData(); PatientData patientData = new PatientData(); int iRec = -1; for (int i = 0; i < patientDataVector.size(); i++) { tempPatientData = (PatientData) patientDataVector.elementAt(i); String tempCustNum = tempPatientData.getIdPatientString().trim(); if (custRecNum.equals(tempCustNum)) { patientData = new PatientData(); patientData = (PatientData) patientDataVector.elementAt(i); iRec = i; } }
for (Iterator iterator1 = nestedElements1.iterator(); iterator1.hasNext();) { Element o1 = (Element) iterator1.next();
if (o1.getName().equals("Address") == true) { patientData.setCorrectedAddressLine1(o1.getTextTrim()); } else if (o1.getName().equals("City") == true) { patientData.setCorrectedCity(o1.getTextTrim()); } else if (o1.getName().equals("TimeToProcess") == true) { patientData.setTimeToProcess(o1.getTextTrim()); } else if (o1.getName().equals("AddressErrorString") == true) { patientData.setAddressErrorString(o1.getTextTrim()); } else if (o1.getName().equals("State") == true) { patientData.setCorrectedState(o1.getTextTrim()); } else if (o1.getName().equals("Zip") == true) { patientData.setCorrectedZip(o1.getTextTrim()); } else if (o1.getName().equals("Plus4") == true) { patientData.setCorrectedZip4(o1.getTextTrim()); } else if (o1.getName().equals("PhoneNewAreaCode") == true) { patientData.setPhoneNewAreaCode(o1.getTextTrim()); } else if (o1.getName().equals("CarrierRoute") == true) { patientData.setCarrierRoute(o1.getTextTrim()); }
Hmm. interesting. I read the experts exchange and got that they don't really like JDOM too much. I'd rather not increase memory because this app needs to run on peoples computers with smaller memory. (like 128MB or so, not my 512MB computer).
I've slashed my code that creates the XML down using JDOM and I'm posting that here. (slahed to make it more readable) The code that is here is actually the end result of a "output buffer" I wrote to control the number of "records" stuffed into each XML. I can set that number to limit the size of my XML files. I've currently had it at "25" records which yields relatively small XML files (maybe 20K most).
Here is the creating XML code. I'm posting separately the stuff that pulls it apart. Since this chunk of code gets executed repeatedly, I'm wondering if there is something special I would need to do do release resources? I don't explicitly mention a "Document" class I don't think.
class Example {
// Create the root element
Element recordSetElement = new Element("RecordSet");
recordSetElement.addContent(new Element("CustomerID").addContent(sCustID));
Element recordElement;
for (int i = 0; i < patientDataVector.size(); i++) {
PatientData patientData = (PatientData) patientDataVector.elementAt(i);
}
sFullName = patientData.getName(1);
sCompany = "";
sAddress = patientData.getAddress();
recordElement = new Element("Record");
recordElement.addContent(new Element("ErrorString").addContent(""));
recordElement.addContent(new Element("CustRecNo").addContent(sPatientId));
recordElement.addContent(new Element("Address").addContent(sAddress));
recordElement.addContent(new Element("Address2").addContent(sAddress2));
recordElement.addContent(new Element("City").addContent(sCity));
recordElement.addContent(new Element("State").addContent(sState));
recordSetElement.addContent(recordElement);
}
XMLOutputter outputter = new XMLOutputter(" ", true);
String sendXML = outputter.outputString(recordSetElement);
// here comes servlet stuff, the code below is a cut and paste from the Melissa Data Java Example provided
/** Set the URL with what was entered in the GUI */
url = new URL(sHttpAddress);
/** Establish the connection */
HttpURLConnection urlConn = (HttpURLConnection) url.openConnection();
urlConn.setDoInput(true);
urlConn.setDoOutput(true);
urlC onn.setUseCaches(false);
urlConn.setRequestMethod("POST");
urlConn.setRequestPro perty("Accept-Language", "en");
urlConn.setAllowUserInteraction(false);
urlConn.setRequestProperty("Cont ent-length", String.valueOf(param.length()));
urlConn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
DataOutputStream out = new DataOutputStream(urlConn.getOutputStream());
out.writeBytes(param);
out.flush() ;
out.close();
BufferedReader in = new BufferedReader(new InputStreamReader(urlConn.getInputStream()));
xmlOutputLine = in.readLine();
in.close();
/** Close the connection */
urlConn.disconnect();
}
and, as promised, here is the code that takes the response XML doc and pulls it apart. Someplace it seems that memory is getting absorbed and not put back.
class Example {
SAXBuilder builder = new SAXBuilder(false);
org.jdom.Document doc = null;
StringReader sr = new StringReader(xmlString);
doc = builder.build(sr);
Element root = doc.getRootElement();
List nestedElements = root.getChildren();
// This is running through records like: RecordSet;CustomerId;Record
for (Iterator iterator = nestedElements.iterator(); iterator.hasNext();) {
Element o = (Element) iterator.next();
if (o.getName().equals("Record") == true) {
// We are running through the return record, getting out of it what we need
List nestedElements1 = o.getChildren();
// First, get CustRecNo out of Record
String custRecNum = new String("");
// This is going through the details of the Record. like: ErrorString,FullName,CustRecNo,etc.
for (Iterator iterator1 = nestedElements1.iterator(); iterator1.hasNext();) {
Element o1 = (Element) iterator1.next();
if (o1.getName().equals("CustRecNo") == true) {
custRecNum = o1.getTextTrim();
}
}
// now, localize which patientrecordvector we need to update
PatientData tempPatientData = new PatientData();
PatientData patientData = new PatientData();
int iRec = -1;
for (int i = 0; i < patientDataVector.size(); i++) {
tempPatientData = (PatientData) patientDataVector.elementAt(i);
String tempCustNum = tempPatientData.getIdPatientString().trim();
if (custRecNum.equals(tempCustNum)) {
patientData = new PatientData();
patientData = (PatientData) patientDataVector.elementAt(i);
iRec = i;
}
}
for (Iterator iterator1 = nestedElements1.iterator(); iterator1.hasNext();) {
Element o1 = (Element) iterator1.next();
if (o1.getName().equals("Address") == true) {
patientData.setCorrectedAddressLine1(o1.getTextTrim());
} elseif (o1.getName().equals("City") == true) {
patientData.setCorrectedCity(o1.getTextTrim());
} elseif (o1.getName().equals("TimeToProcess") == true) {
patientData.setTimeToProcess(o1.getTextTrim());
} elseif (o1.getName().equals("AddressErrorString") == true) {
patientData.setAddressErrorString(o1.getTextTrim());
} elseif (o1.getName().equals("State") == true) {
patientData.setCorrectedState(o1.getTextTrim());
} elseif (o1.getName().equals("Zip") == true) {
patientData.setCorrectedZip(o1.getTextTrim());
} elseif (o1.getName().equals("Plus4") == true) {
patientData.setCorrectedZip4(o1.getTextTrim());
} elseif (o1.getName().equals("PhoneNewAreaCode") == true) {
patientData.setPhoneNewAreaCode(o1.getTextTrim());
} elseif (o1.getName().equals("CarrierRoute") == true) {
patientData.setCarrierRoute(o1.getTextTrim());
}
}
}