ColdFusion jvm no garbage collection

I have a cfc method that iterates over a list and makes a series of SOAP calls through cfhttp. Then inserts the result into the database.

The process itself copes with the fact that the java memory is slowly filling up and ultimately (depending on the number of elements in the returned records) simply stops working. There is no mistake or anything visible that it just stops. If I look at the application log file through the coldfusion administrator, I see one or both of the following errors:

GC overhead limit exceeded The specific sequence of files included or processed is: 

or

 Java heap space The specific sequence of files included or processed is: 

The following is a simplified version of the code I'm running:

 <cfsetting requesttimeout="3600"> <cfloop condition="thisPass lt 10"> <cfscript> runtime = CreateObject("java","java.lang.Runtime").getRuntime(); objSystem = CreateObject( "java", "java.lang.System" ); soapBody = ''; soapResponse = ''; thisStruct = ''; lock scope='application' type='exclusive' timeout='60' { //This is where I am trying to manage the memory and call garbage collection try { freeMemory = runtime.freeMemory()/1024/1024; writeOutput("- fm = "&freeMemory); if (freeMemory < 200){ objSystem.gc(); sleep(1000); writeDump(' - dumping freeMemory'); } } catch(any error) { writeDump(' - trying to dump GC as '&now()& ' freeMemory = '&freeMemory); } } </cfscript> <cfsavecontent variable="soapBody"> <?xml version="1.0" encoding="utf-8"?> [ BUILD SOAP ENVELOP ] </cfsavecontent> <cfhttp url="[URL]" method="post" result="httpResponse" timeout="600" resolveurl="false"> <cfhttpparam type="header" name="SOAPAction" value="[URL2]" /> <cfhttpparam type="xml" value="#trim( soapBody )#"/> </cfhttp> <cfscript> soapBody = ""; soapResponse = httpResponse.fileContent; soapResponse = xmlParse( soapResponse ); thisStruct = xmlSearch(soapResponse,'/soap:Envelope/soap:Body/')[1].xmlChildren[1].xmlChildren[1].xmlChildren; writeOutput("-"&arrayLen(thisStruct)&' records'); getPageContext().getOut().flush(); if(arrayLen(thisStruct) == 2500){ thisPass = thisPass+1; } else { writeOutput("- total records = "&(2500*(thisPass-1))+arrayLen(thisStruct)); thisPass = 100; // since looping while thisPass lt 10 this should prevent the next iteration } </cfscript> <cfloop from="1" to="#arrayLen(thisStruct)#" index="i"> [RUN PROC TO INSERT RECORDS] </cfloop> </cfloop> 

It seems that the GC sometimes releases a bit of memory, but not with any kind of reliability. I understand that GC () is just a recommendation for java to free some of the unused memory, but I'm not sure how I can get it to make it free memory. It is possible that there is a leak somewhere, but I do not see this. I hope this is something obvious that I already looked, and I admit that my knowledge in java is extremely limited.

Is there any java guru that can see my error?

UPDATE: The following is an example of the output, which is a helpfule to see the memory reduction.

there are 236 lists that will go through

  • 88185 - fm = 293.564407349 -6 records- total records = 6
  • 88389 - fm = 290.86995697 -116 records- total records = 116
  • 88390 - fm = 308.382568359 -262 records- total records = 262
  • 88839 - fm = 292.707099915 -2032 records- total records = 2032
  • 91088 - fm = 290.711753845 -6 entries- total entries = 6
  • 92998 - fm = 287.754066467 -5 records - total records = 5
  • 95510 - fm = 309.919425964 -91 records- total records = 91
  • 96478 - fm = 292.035064697 -1180 records- total records = 1180
  • 96479 - fm = 259.001213074 -1113 records- total records = 1113
  • 96480 - fm = 261.121406555 -110 records - total records = 110
  • 96796 - fm = 267.235244751 -2 records- total records = 2
  • 96799 - fm = 265.037582397 -0 records- total records = 0
  • 97435 - fm = 263.589103699 -2500 records - fm = 227.629760742 -2500 records - fm = 200.85987854 -2500 records - fm = 202.156776428 -2500 records - fm = 166.366210938 - dumping freeMemory -656 records- total records = 10656
  • 98173 - fm = 160.579734802 - dumping freeMemory -35 records- total records = 35
  • 99111 - fm = 176.218482971 - dumping freeMemory -0 records- total records = 0
  • 100998 - fm = 194.708694458 - dumping freeMemory -185 records- total records = 185
  • 101811 - fm = 160.61415863 - dumping freeMemory -2500 records - fm = 112.862670898 - dumping freeMemory -2500 records - fm = 86.2071380615 - dumping freeMemory -2500 records - fm = 52.9639358521 - dumping freeMemory -1064 records- total records = 8564
  • 105014 - fm = 56.1721343994 - dumping freeMemory -14 records- total records = 14
  • 105992 - fm = 73.0022964478 - dumping freeMemory -14 records- total records = 14
  • 107539 - fm = 75.9522399902 - dumping freeMemory -93 records- total records = 93
  • 107580 - fm = 58.345199585 - dumping freeMemory -2500 records
+4
source share
4 answers

After many searches, I found that the best “fix” for these specific problems was to remove the code that tried to garbage collect and increase the size of the java heap. In the file /jrun/bin/jvm.config.

Changing Arguments in VM to:

 java.args=-server -Xms2048m -Xmx2048m -Xmn1024m -Dsun.io.useCanonCaches=false -XX:MaxPermSize=192m -XX:+UseParallelGC -Xbatch -Dcoldfusion.rootDir={application.home}/ -Djava.security.policy={application.home}/servers/cfusion/cfusion-ear/cfusion-war/WEB-INF/cfusion/lib/coldfusion.policy -Djava.security.auth.policy={application.home}/servers/cfusion/cfusion-ear/cfusion-war/WEB-INF/cfusion/lib/neo_jaas.policy 

I managed to increase the initial heap size (Xms) and the maximum heap size (Xmx) to 2048 m, and the heap size of the “young generation” (Xmn) to 1024 m. I was suggested that the young generation should be smaller than the initial and maximum for better collection garbage.

As suggested by James , I commented on the actual processes (which are in the function and var'd), and then uncommented them in turn each time. What I learned from this was that the big SOAP responses were what filled the memory, and not flow, as I was afraid.

As Adam mentioned, it was not about Java running the GC, but that there wasn’t enough room for the management I was throwing at (for some reason CF doesn't like to deal with 2500 records of SOAP responses very well) go figure .

Adam was also right in saying that the problem with deleting Java memory in CF is "dark art." Using the server monitor http://localhost/CFIDE/administrator/monitor/launch-monitor.cfm and switching to the statistics tab in the section "Memory usage" → "Memory usage" I could observe how the memory slowly fills up and is reset itself, even when after a new reboot, there are no processes where it is running. I could never understand why, but I could see which levels work and what I got to the top.

The default memory allocated in the jvm.config file was 512 m, and was simply not enough to handle what was happening. There may be a better way to handle this general process. You may have to implement Henry's suggestion and put it in the database and skip it, although that sounds very awkward for me.

I’m sure that others, then CF now grabs a huge chunk of resources right out of the gate, there may be other problems with this solution, but (at the moment) it works as needed.

UPDATE: I changed the cfc function so that instead of inserting everything into the database, I would write all the XML files and then read the file and paste it into the database. Somehow, writing to the file allowed java to "breathe" long enough to execute GC ().

+1
source

This is not a case where Java does not manage the GC very well, it is a case where you do not control what you put in (and extract from ~) memory so that things are accessible to the garbage collector to clean them. You (trying ~) to treat a symptom, not a problem here.

See what happens in memory and why the material you expect to be GCed is not GCed. Perhaps you have links to things in a common area (unexpectedly) or something like that. Fixing these issues with ColdFusion on top of Java is a bit of a dark art.

But do not try to "fix" the "problem" of things that are not GCed, when you press GC, fix the problem that causes your memory to: a) fill; b) not be GC-capable if you think it should be.

+1
source

I can say that the power GK approach didn’t help me much when I tried this. In general, here is a list of things to try first:

  • Make sure the objects you call the variables use var or local
  • If you can move processing to a database, do it
  • <cfdump> , <cfdump> very difficult. If you really need to use it, focus only on the part of the variable that you need. Also use text format
  • Modify the JVM to use more memory
  • Use Java 1.7 and G1GC. (Do this with caution, as it may not yet be supported).
  • Use fewer query requests

Here is a list of what I will consider for your code above

  • I would move everything inside the view to a function and var scope soapbody soapResponse, thisStruct
  • After I finished with thisStuct, I would StructClear(thisStruct);
  • Get the entry writedump(); where they are heavy like <cfdump>
+1
source

AFAIK CF is not suitable for long queries. From what I heard, the memory is not freed until the request is complete.

We tried to break up a long request into smaller requests that CF can manage, and memory will usually be released after the request is completed.

One obsolete system that we use will insert the task (s) into the database table, and the CF Scheduler will work simultaneously with the package. I hated it because of latency, but this is what had to be done in the days of CF7, and since then it has not improved.

0
source

All Articles