Managing the Heap in Salesforce.com

With the Spring '10 release, Salesforce.com removed the limit on the number of items a collection can hold. So now, instead of ensuring that your collections contain no more than 1000 items, you have to monitor your heap size. Here are some strategies on how to write Apex scripts that run within these limits.

First of all, what is the heap? Dynamic memory allocation (also known as heap-based memory allocation) is the allocation of memory storage for use in a computer program during the runtime of that program. In Apex the heap is the reference to the amount of memory used by your reachable objects for a given script and request. When you create objects in your Apex code, memory is allocated to store these objects.

As with many other things in Force.com, there are governors and limits that prevent you from hijacking the heap and degrading the performance of other running applications. The heap limit is calculated at runtime and differs on how your code is invoked:

  • Triggers - 300,000 bytes
  • Anonymous Blocks, Visualforce Controllers, or WSDL Methods - 3,000,000 bytes
  • Tests - 1,500,000 bytes

These limits also scale with trigger batch sizes:

  • For 1-40 records, the normal limits apply
  • For 41-80 records, two times the normal limits apply
  • For 81-120 records, three times the normal limits apply
  • For 121-160 records, four times the normal limits apply
  • For 161 or more records, five times the normal limits apply

Luckily Salesforce.com increased the heap size limits in Summer '10 but you still may run into some issues. Here are a few things you can do to write heap-friendly code.

Watch the Heap

When your scripts run you can view the heap size in the debug logs. If you notice your heap approaching the limit, you will need to investigate why and try to refactor your code accordingly.

Use the Transient Keyword

Try using the "Transient" keyword with variables in your controllers and extensions. The transient keyword is used to declare instance variables that cannot be saved, and shouldn't be transmitted as part of the view state for a Visualforce page.

Use Limit Methods

Use heap limits methods in your Apex code to monitor/manage the heap during execution.

  • Limits.getHeapSize() - Returns the approximate amount of memory (in bytes) that has been used for the heap in the current context.
  • Limits.getLimitHeapSize() - Returns the total amount of memory (in bytes) that can be used for the heap in the current context.


// check the heap size at runtime
if (Limits.getHeapSize > 275000) {
// implement logic to reduce
}

One strategy to reduce heap size during runtime is to remove items from the collection as you iterate over it.

Put Your Objects on a Diet

If the objects in your collection contain related objects (i.e., Account objects with a number of related Contacts for each) make sure the related objects only contain the fields that are actually needed by your script.

Use SOQL For Loops

SOQL "for" loops differ from standard SOQL statements because of the method they use to retrieve sObjects. To avoid heap size limits, developers should always use a SOQL "for" loop to process query results that return many records. SOQL "for" loops retrieve all sObjects in a query and process multiple batches of records through the use of internal calls to query and queryMore.

for (List<Contact> contacts : [select id, firstname, lastname 
 from contact where billingState = 'NY']) {

 // implement your code to modify records in this batch

 // commit this batch of 200 records
 update contacts;
}

Note: There used to be a strategy for dealing with heap intensive scripts by moving them asynchronous, @Future methods. However, since the heap limits were increased in Summer '10 this is no longer a reason to simply use @Future method as the limits are the same.

Any other ideas on how to effectively manage the heap?