If you are a salesforce developer or admin, there are scenarios where you might have encountered this error message ” System.LimitException: Apex heap size too large: 6005934″. 😳 I recently solved this problem for one of my clients and decided to write a post on it. 😉 This post will walk you through causes of this issue and what are ways you can fix it and prevent it from happening?
Why does this error happen?
In traditional programming languages like Java, dotnet etc the use of memory like querying a table with more than 50,000 records and storing it in a collection like a map or arraylist is a common practice. This is done to prevent unwanted database calls every time to get the results you want and instead get the values from the collection. Now this approach does not work in apex environment. The reason is that salesforce is a shared database and salesforce ensures that there is a limit for putting stuff on memory causing the issue.
Now if the above paragraph does not make sense to you, think about your iphone where you have a limited memory. If you load too many apps or have too many images, your mobile phone complains that you are running out of space . Of course you can add more memory to your iphone but in salesforce memory is expensive and you will not win the game with Salesforce on this.
So Where do you start to debug this issue?
Check Soql queries
If you look at the error message, salesforce will point to a trigger or apex class which is causing this problem. So once you narrow down the apex trigger or class, you want to check for all the SOQL statements used by the apex class or trigger. If you find any soql statement without a where clause or which returns more than 30,000 records , that is the first cause of the problem. The reason is once the query happens, you are storing those huge records in memory causing the error message. The below screen shot is an example of a SOQL query which is the source of the problem. You need to enable your debug log to see this problem.
Check collection objects
The second source of the problem is the collection objects you use like maps, arraylists or Sets. If you find the SOQL statement which returns more number of records, the result of the records are stored in this collection. Identify the code which loops through the collection or gets a value based on the key. Now this collection will hold the entire 30,000 records or more in memory and it continues to loop through the records to find the value. This is a big red flag which needs to be removed.
Other Areas to troubleshoot
Here is a possible set of things which you can check for other than big SOQL Queries and collections.
- If you are using multiple currency and you are querying to get the latest conversion rate for a currency by a SOQL statement, it is a certain cause.
- If you have custom objects having more than 30,000 records like countries, list of tax rates etc where the code is querying every time to get a particular value, it could be a potential cause .
How to fix the problem.
- Once you have identified the problem to be a big SQOL statement displaying 30,000 records, you want to make sure that you put a where condition on the SOQL and query the records based on a date or a condition which would return 1 to 5 records maximum instead of returning the entire record set.
- If the cause of the problem is a collection object where you have loaded everything in memory, try to remove the collection or restrict it to a few records by tuning the SOQL and get the record you want. You should think about rewriting the code.
- Look at the debug log with profiling filter set to finest. Look for any method, SOQL statement executed more than multiple times due to duplicate calls . This can easily add more records to the collection causing it to blow out. So remove duplicate code or calls and minimize them.
- One possible side effect of the problem is that you might try to cheat the system by creating a static instance and ensure your trigger is called one time only without fixing the real SOQL. Now this would cause TOO many rows errors . So make sure you remove this completely.
The below screen shot shows a soql limit error if you do not fix your code correctly.
The below screen shows how i fixed the soql code by putting a where condition on the soql instead of loading everything in memory.
Key Takeaways
- If you find the heap size error, it is always caused by SOQL statement returning more than 30,000 records or more or collection objects holding too much records in memory.
- To fix it, remove the SOQL statement and put a where condition to return a limited records like 1 to 5 and fine tune any collection object.
- If you want to prevent this from happening, look out for custom objects or currency records where you are continously loading records every week to maintain them. Any apex code or trigger looking at this object needs to revisited.
I hope this post has helped you to fix your dreaded heap size limit issue. As always feel free to post your thoughts or questions or email me at buyan@eigenx.com for further questions and I will be glad to answer it for you.
Please subscribe
Subscribe to our mailing list and get tips to maximize salesforce to your email inbox.
I am honored to have your subscription. Stay tuned for tips to maximize your salesforce investment
Something went wrong.
Hi Buyan,
Thank you for putting such nice blog. This is really helpful.
One more thing we can do is to use SOQL For Loops. Like whenever we have a requirement to loop over a set of records return by an SOQL, we first store those records in the collection and then iterate those collections to perform the action on the data which would certainly eat up the memory. Using SOQL for loop we have directly use the SOQL inside for loop instead of collection variable, this way the memory will be used in runtime whenever required. More details about SOQL For Loop can be found at https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/langCon_apex_loops_for_SOQL.htm
Thank You again !!
-Nilesh Dethe
Hi Nilesh,
Great point!! SOQL FOR Loop is a great technique which should be used in soql going forward..
Buyan