Troubleshooting a java.lang.StackOverflowError in a Groovy script.

I was hoping that someone could point out a flaw in the following script or a good way to troubleshoot this script. I know that it is happening in the createServices function and assume that it is related to the level of recursion.

The script is derived from: [link]www.foglight.org/.../Default.aspx


def createOrUpdateObject(typeName, propertyValues) {
topologyService = server.TopologyService;

def type = topologyService.getType(typeName);
def objectShell = topologyService.getObjectShell(type);
propertyValues.each ({propertyName, propertyValue ->
def property = type.getProperty(propertyName);
if (!property.isMany()) {
objectShell.set(property, propertyValue);
}
else if (propertyValue instanceof Collection) {
objectShell.getList(property).addAll(propertyValue);
}
else {
objectShell.getList(property).add(propertyValue);
}
});
return topologyService.mergeData(objectShell);
}

def deleteObject(typeName, objName) {
topologyService = server.TopologyService;
object = createOrUpdateObject(typeName, objName);
def args = [];
args.add(object);
topologyService.deleteObjects(new HashSet(args));
}

def createServices(parent) {
object = createOrUpdateObject(parent['type'], [name: parent['name']]);
objects = [];
if(parent['children']) {
for(child in parent['children']) {
objects.add(createServices(parent));
}
} else {
objects = createDynamicServices(object);
}
object = createOrUpdateObject(object.get("topologyTypeName"), [name:object.get("name"), definition: objects]);
return object;
}

def deleteServices(parent) {
if(parent['children']) {
for(child in parent['children']) {
deleteServices(child);
}
}
object = createOrUpdateObject(parent['type'], [name: parent['name']]);
deleteDynamicServices(object);
deleteObject(parent['type'], [name: parent['name']]);
}

def deleteDynamicServices(parent) {
for (tier in ['OS', 'Application', 'Database', 'Network', 'Web', 'End User']) {
deleteObject("FSMDynamicManagedComponent", [name: tier + " (" + parent['name'] + ")", container: parent]);
}
}

def createDynamicServices(parent) {
def services = [];
for (tier in ['OS', 'Application', 'Database', 'Network', 'Web', 'End User']) {
services.add(
createOrUpdateObject(
"FSMDynamicManagedComponent",
[
name: tier + " (" + parent['name'] + ")",
container: parent,
componentQuery: "Agent where annotations like '%tier: " + tier + "%'",
queryConditions: "annotations like '%tier: " + tier + "%'",
baseQuery: "/modules[fqId='system:foglight']/queries[fqId='system:foglight.8']"
]
)
);
}
return services;
}

def tree = [type: "FSMCategory", name: "aa", children: [
[type: "FSMService", name: "ab", children: [
[type: "FSMService", name: "bb"]]],
[type: "FSMService", name: "ac", children: [
[type: "FSMService", name: "ba"],
[type: "FSMService", name: "az"],
[type: "FSMService", name: "aw"]]],
[type: "FSMService", name: "ad", children: [
[type: "FSMService", name: "ax"],
[type: "FSMService", name: "aw"],
[type: "FSMService", name: "av"],
[type: "FSMService", name: "au"],
[type: "FSMService", name: "at"],
[type: "FSMService", name: "as"]]],
[type: "FSMService", name: "ae", children: [
[type: "FSMService", name: "ar"],
[type: "FSMService", name: "aq"]]],
[type: "FSMService", name: "af", children: [
[type: "FSMService", name: "ap"],
[type: "FSMService", name: "ao"]]],
[type: "FSMService", name: "ag", children: [
[type: "FSMService", name: "an"]]],
[type: "FSMService", name: "ah", children: [
[type: "FSMService", name: "am"],
[type: "FSMService", name: "al"]]],
[type: "FSMService", name: "ai", children: [
[type: "FSMService", name: "ak"],
[type: "FSMService", name: "aj"]]]]];

deleteServices(tree);
createServices(tree);

Parents
  • A StackOverflowError is simply signals that there is no more memory available. It is to the stack what an OutOfMemoryError is to the heap: it simply signals that there is no more memory available. JVM has a given memory allocated for each stack of each thread, and if an attempt to call a method happens to fill this memory, JVM throws an error. Just like it would do if you were trying to write at index N of an array of length N. No memory corruption can happen. The stack can not write into the heap.

    The common cause for a stackoverflow is a bad recursive call. Typically, this is caused when your recursive functions doesn't have the correct termination condition, so it ends up calling itself forever. Or when the termination condition is fine, it can be caused by requiring too many recursive calls before fulfilling it.

    Here's an example:

    public class Overflow {
        public static final void main(String[] args) {
            main(args);
        }
    }

    That function calls itself repeatedly with no termination condition. Consequently, the stack fills up because each call has to push a return address on the stack, but the return addresses are never popped off the stack because the function never returns, it just keeps calling itself.

Reply
  • A StackOverflowError is simply signals that there is no more memory available. It is to the stack what an OutOfMemoryError is to the heap: it simply signals that there is no more memory available. JVM has a given memory allocated for each stack of each thread, and if an attempt to call a method happens to fill this memory, JVM throws an error. Just like it would do if you were trying to write at index N of an array of length N. No memory corruption can happen. The stack can not write into the heap.

    The common cause for a stackoverflow is a bad recursive call. Typically, this is caused when your recursive functions doesn't have the correct termination condition, so it ends up calling itself forever. Or when the termination condition is fine, it can be caused by requiring too many recursive calls before fulfilling it.

    Here's an example:

    public class Overflow {
        public static final void main(String[] args) {
            main(args);
        }
    }

    That function calls itself repeatedly with no termination condition. Consequently, the stack fills up because each call has to push a return address on the stack, but the return addresses are never popped off the stack because the function never returns, it just keeps calling itself.

Children
No Data