1

I have a Visualforce page that, once an action method is called, performs lots of calculations and then displays data on the page.

I am hitting the synchronous heap size limit of 6MB and I want to leverage asynchronous processing so that I can increase the heap size to 12MB.

As @future methods are void, what approaches can I take to refactor my constructor to be able to bypass the 6MB limit?

1

Two possible approaches are possible if you simply can't get past the limits.

First, you can do client-side rendering and calculation with RemoteAction methods or Remote Object invocations to get the data you need. This is generally acceptable if you're looking at a significant amount of data, and it gets really good performance, as JavaScript is far faster than Apex Code. RemoteAction methods can return 15MB of data, and you're not likely to hit the heap limit since the execution time would be short.

Second, you can do asynchronous processing, but you'll need some Queueable code. Use System.enqueueJob to start the processing, and get the Job ID. Then, poll the server until the job reports as completed, then finally query the data back from the database. Note that this means you'll need to arrange a mechanism to determine where the results were stored. It's certainly complicated, but possible.

  • can you point me to 15MB heap size limit for Remote Actions. As far as I aware only truly async methods like @future/queueables get more heap. Also, your answer: salesforce.stackexchange.com/questions/54364/… – dzh Jan 8 at 4:51
  • @dzh CPU and heap are only checked periodically and are therefore flexible. I wrote a script that you can try out in execute anonymous that demonstrates this principle. The limit itself is in the documentation. The proposal for this answer is to grab all the data and then client-side process, since there's no governor limits in a browser. – sfdcfox Jan 8 at 5:16
4

I think you need to live within the 6M limit.

The first thing to do though is to understand what is taking up the space by reviewing your code and thinking about the likely sizes of what you are outputting. (A classic extreme example is querying the body field of Attachments where each body can be up to 5M in size.) You may be able to compromise with what you output e.g. only showing the first 80 characters of strings that could be many thousands of characters long.

Also be aware of Setting Read-Only Mode for an Entire Page thst helps with other limits.

Your intermediate steps my be causing the heap problem. A couple of examples...

Patterns such as this SOQL For Loop:

for (MyType__c t : [select ... from MyType__c ...]) {
    ...
}

avoids heap space being occupied by all the records queried. Instead the records are queried in batches.

You can also discard intermediate results as soon as they are no longer needed:

List<Something> bigList1 = ...;
List<Something> bigList2 = ...;

List<Something> intermediateResult = ...;
bigList1 = null;
bigList2 = null;

// Heap space for bigList1 and bigList2 now free for other use

because Apex is a garbage collected language where once an object reference is no longer reachable by the code the space occupied by the object can be re-used for other objects.

And also bear in mind that not all problems are suited to a simple Visualforce solution. For example, a more complicated Visualforce page can make multiple JavaScript requests mack to an Apex controller class and so break the problem down into multiple pieces each of which fits within the 6M Apex heap limit.

  • Thanks Keith. I've optimized my code as much as I can. Unfortunately, due to the amount of calculations in the transaction it is performing, I'm hitting the limit. I can't reduce the calculations and so it seems I'm stuck. As @future doesn't return anything, it seems I can't use it in with my use case (visualforce page). – Andy Hitchings May 22 '18 at 20:57
  • 1
    @AndyHitchings But you can make multiple async requests from the page if you can breakup the problem into pieces and assemble the chunks of result in the page. – Keith C May 22 '18 at 21:08
  • Thanks Keith. Can you elaborate on the 'assemble the chunks of result in the page'? Since @future is void, how can I use it in that way? Thank you! – Andy Hitchings May 22 '18 at 22:08
  • 1
    @AndyHitchings You write an RemoteAction Apex method not a future one. Then you call that method multiple times using JavaScript and providing you can break the work up into chunks that reduces the server-side heap to below 6M per request, you can re-assemble and present the results by creating DOM elements. – Keith C May 22 '18 at 23:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.