Memory Leak in Java SDK ?

Hello

I have a big issue using the XIR2 SDK when I want to get rights for an object (universe or overload for example). When I start my process the memory used keep growing, starting for 20 mb to more than 100mb and if I hav too many objects, the script hang. Here my code :

try {
			// TODO Auto-generated method stub
			String boQuery="SELECT * FROM CI_APPOBJECTS WHERE SI_KIND='OVERLOAD'";
			Iterator<IOverload> itAllUniverses = BoxiRepositoryManager.getInstance().executeQuery(boQuery).iterator();
			
			IOverload myIOverload = null;
			while(itAllUniverses.hasNext()) {
				myIOverload = itAllUniverses.next();
				System.out.println("Universe = "+myIOverload.getTitle());
				
				ISecurityInfo i = myIOverload.getSecurityInfo();
				Iterator<IObjectPrincipal> iob = i.getObjectPrincipals().iterator();
				
				int securityID_highBytes = 0;
				int overload_SI_OBTYPE = ((Integer) myIOverload.properties().getProperty("SI_OBTYPE").getValue()).intValue();
				
				IObjectPrincipal ciob = null;
				while(iob.hasNext()) {
					ciob = iob.next();
					Iterator<ISecurityRight> irob = ciob.getRights().iterator();					
					
					ISecurityRight oSecurityRight = null;
					while (irob.hasNext()) {
						oSecurityRight =  irob.next();

						//Retrieving the high byte of the Security Right ID and compare with the SI_OBTYPE of the overload
						securityID_highBytes = (int) oSecurityRight.getID()/(256*256);
						if (securityID_highBytes==overload_SI_OBTYPE) {
							System.out.println("	Principal = "+ciob.getName());
						}
					}
				}
			}
		} catch(Exception e) {
			
		}

The error

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
	at java.util.Hashtable.rehash(Unknown Source)
	at java.util.Hashtable.put(Unknown Source)
	at com.crystaldecisions.sdk.occa.security.internal.a.a(Unknown Source)
	at com.crystaldecisions.sdk.occa.security.internal.f.new(Unknown Source)
	at com.crystaldecisions.sdk.occa.security.internal.a.commit(Unknown Source)
	at com.crystaldecisions.sdk.occa.infostore.internal.ap.a(Unknown Source)
	at com.crystaldecisions.sdk.occa.infostore.internal.ar.if(Unknown Source)
	at com.crystaldecisions.sdk.occa.infostore.internal.ar.getObjectPrincipals(Unknown Source)
	at com.crystaldecisions.sdk.occa.infostore.internal.ar.getObjectPrincipals(Unknown Source)

For me there is a memory leak somehere in the getObjectsPrincipals or getRights method but maybe I’m doing this in a bad way but i really dont understand why the memory is not release…

Thanks for you help

PS : sorry for my grammar I’m french :slight_smile:


Oreste (BOB member since 2006-06-28)

It looks to me like you’ll need to adjust your code to only extract “blocks” of query results at a time so your object isn’t consuming as much memory.

Either that, or a quick fix may be to just allocate more memory to your JVM at runtime: (i.e. -Xmx###m) when you run your program.


crystal01 :us: (BOB member since 2006-08-30)

Thanks a lot Crystal for your answer ! But what do you mean by “you’ll need to adjust your code to only extract “blocks” of query results at a time”

Do you mean that I should query for only 1 overload in my query at a time and not retrivere all in one shot ?

For the JVM trick I was aware about it but for me its not really a solution, I want to try to optimize my code first :slight_smile:

Thanks again


Oreste (BOB member since 2006-06-28)

By “blocks”, I mean perhaps 500 or 1000 objects at a time. So your query would loosely look something like this pseudocode:

blockRetrieveCount = 1
lastProcessedID = 0

while (blockRetreiveCount > 0)
{
  query("select top " + blockSize + " from ci_infoobjects where.... and si_id > lastProcessedID order by si_id")
  
  ...processing / record write / whatever you're doing with results...

  blockRetrieveFlag = query.ResultSetSize
  lastProcessedID = queryResults.property(SI_ID)
}

I’d give something like this a shot to see if it helps with memory consumption. Also, make sure you’re explicitely nulling your query result objects when you’re done with them so they’re free’d up for garbage collection.


crystal01 :us: (BOB member since 2006-08-30)

Hello

I tried your solution by retriving only one row at a time in a loop and nulling all my objects after using them (even if in Java we dont need to do that with the garbage collector) but it doesn’t work I still have the memory usage which keeps growing and Im pretty sure that my code is good because if I dont use the methods getRights for IsecurityInfo everything is ok the memory usage is stable (around 30 Mo and with the method --> 120 Mo and more… more… more…). I think that I m going to write to BO support.

Thx again crystal01


Oreste (BOB member since 2006-06-28)

I was having a similar problem to the OP, I wrote a java app that would parse through all web intelligence documents, on our company CMS and output a list of which objects and classes were used by each report into a flat file.

Eventually I would get out of memory errors and the application would crash.

I tried what crystal01 suggested, using blocks of 10 per each IInfoobjects query.

This has done the trick, and my memory usage has now stabilised as opposed to continuously increasing slightly as it was doing previously.

Im guessing that the object containing the query must still hold references to every single report object and so the java garbage collection was not reclaiming the memory when I had finished with a report.

Thanks Crystal I had spent 2 weeks trying to solve this issue with little success.


sjohal112 (BOB member since 2008-07-23)

I think that is the problem. When you retrieve your IInfoObjects collection, try calling infoObjects.remove(x) instead of using an iterator. This would be in addition to nulling references to individual IInfoObject objects to allow for garbage collection.


BoB LoblaW :us: (BOB member since 2007-10-23)

Revisiting this old topic - did you by chance get confirmation that there is a memory issue with the getObjectPrincipals() method? I’m seeing some similiar behaviour specifically with this method.


crystal01 :us: (BOB member since 2006-08-30)

I got confirmation from SAP that there is indeed a memory leak in the getObjectPrincipals() method in the Java SDK. This leak was corrected in XI R2 SP5 for the COM and .NET SDKs, but apparently the Java version was not. I’m not holding my breath that this will be corrected either, as XI R2 is nearing support end of life.


crystal01 :us: (BOB member since 2006-08-30)

I ran into this problem with a script I was working on last month. Good to know it wasn’t my coding!

I modified my script to work in XI3 with the new security model. I did not find a memory leak there.

Joe


joepeters :us: (BOB member since 2002-08-29)

Has anyone gotten any further information from SAP on this memory leak or better yet how to code around it on the R2 platform? I have a SAP note open on the issue, but have not been able to get clear direction on how / if this can be worked around.

I have tried:

  • nulling all relevant objects
  • explicit garbage collection
  • varying batch sizes for my IInfoObjects collection

with no success.

So long as getObjectPrincipals() is in my code, the available memory will be gradually consumed until a heap space error is thrown.

Curious if anyone has fought with this before…


crystal01 :us: (BOB member since 2006-08-30)

In case this might help anyone, I have found that forcing a periodic session disconnect / re-connect clears out the memory that is held by the getObjectPrincipals() method. It’s a bit of a hackish workaround, but at this point I don’t know that there is a better option.


crystal01 :us: (BOB member since 2006-08-30)

Does it help to move your declarations out of the loop(s)? You use this in a few places:

  while(iob.hasNext()) {
               ciob = iob.next();  
               Iterator<ISecurityRight> irob = ciob.getRights().iterator();   

What if you moved those out of all loops, then just refered to them inside:

  Iterator<ISecurityRight> irob = ciob.getRights().iterator();   
  while(iob.hasNext()) { 
               ciob = iob.next(); 
               irob = ciob.getRights().iterator();

Syntax may not be perfect - but you get the idea?

There are several of these, wonder if you would save memory by a change like this.

Just a thought,
Brent


bdouglas :switzerland: (BOB member since 2002-08-29)