How to Reduce Apex Heap Size Errors

Author: Bruce Tollefson Published: May 11, 2022; Modified: May 11, 2022
code

If you are receiving this error: ‘Apex heap size too large’ it can be difficult to get rid of. Often neglected Heap refers to the amount of memory the transaction is using. If you have to query many objects / records and put them into a list you may run into this issue, especially if there are multiple lists or many fields that are in the query. One way to reduce the heap size error is change how for loops are being used. To demonstrate heap size and one way to reduce the heap size in Salesforce first we will need to create a few records. Let’s go with 5000 for good measure:

List<Account> createList = new List<Account>(); for(Integer i=0; i<5000;i++){ createList.add(new Account(name='Account'+i)); } Insert createList;

If you are doing this in a sandbox the amount of space required is below 5000 records worth HOWEVER if you do this in a single insert it will insert all the records. Your storage will be way above the limit so if you try to create anything else you will need to delete these first which can be done with:

delete [Select Id from Account where CreatedDate = TODAY];//if you created Account records today you can also use where Name LIKE 'Account%'

If you just deleted the records you will need to recreate them before moving on if you would like to follow along.

Next create the following class:

public class TestQueryReturn { public static List<Account> getAccount(){ return [Select Id from Account]; } }

Now we are ready to test.

Testing Apex Heap Size Differences

First we will test the heap size when we return a list of accounts from a method and then loop through them:

Integer i = 0; for(Account test :TestQueryReturn.getAccount()){ i++; if(i == 1)System.debug('_______Heap Size_______ '+Limits.getHeapSize()); }

Note the heap size from the limits.getHeapSize() in the debug. I got 342782, let’s try using a SOQL query List instead of a returned method:

List<Account> testList = [Select Id from Account]; Integer i = 0; for(Account test :testList){ i++; if(i == 1)System.debug('_______Heap Size_______ '+Limits.getHeapSize()); }

Note the heap size from the limits.getHeapSize() in the debug. I got 342780 (nearly identical), let’s try putting the SOQL query into the for loop:

Integer i = 0; for(Account test :[Select Id from Account]){ i++; if(i == 1)System.debug('_______Heap Size_______ '+Limits.getHeapSize()); }

Note the heap size from the limits.getHeapSize() in the debug. I got 7656 (a huge difference), let’s try using a database.query()

Integer i = 0; for(Account test :Database.query('Select Id from Account')){ i++; if(i == 1)System.debug('_______Heap Size_______ '+Limits.getHeapSize()); }

Note the heap size from the limits.getHeapSize() in the debug. I got 7656 again! As we can see when we are querying directly in a for loop with either the SOQL query or database.query() the heap size is significantly smaller.

So why does this happen? When you are querying outside of a for loop you are retrieving all of the records at once. Same as when you are returning a list from another method the full list needs to be retrieved and stored in memory taking up all the heap. However when you are directly querying in a for loop what happens is Salesforce chunks the query into chunks of 2000 records returns that chunk then gets the next until the end, only storing 2000 records at a time in memory. This can be useful if you are querying a large list of records that is only being referenced to augment data and not use a DML operation. Otherwise they list will need to be stored as you would need to do the DML outside of the for loop.

Leave a Reply

Your email address will not be published. Required fields are marked *