Print this page

Troubleshooting System.LimitException: Batchable instance is too big

Knowledge Article Number 000239885
Description If a batch apex class implements Database.Stateful, the instance state is stored in the database.  At this time we do a check against the size of the instance state and the exception is thrown when the Apex Heap Size limit is exceeded. For synchronous Apex the heap size limit is 6 MB and for asynchronous Apex the limit is 12 MB. This exception can obviously occur in a scenario where large collections are persistently maintained.

Even if some chunks fail with this error, the batch job is completed. As per below lines in Batch Apex Developer Guide 
"If the first transaction succeeds but the second fails, the database updates made in the first transaction are not rolled back."

To work around this issue, you can use the following steps:
1. Avoid using Database.Stateful
2. Reduce the amount of persistent data
3. Process less records per batch

In some cases Database.Stateful isn't being implemented or the steps above are not helpful in working around this exception. 
If you've attempted these workarounds and are still seeing this exception, please follow the steps below to find where the heap size is being exceeded.
Resolution 1) Add the following debug method to the affected class:
void checkHeapSize(String tag) {
system.debug(tag + ': Heap size is ' + limits.getHeapSize() + ' enforced is ' + limits.getLimitHeapSize());
2a) Call the method at various points in the code using a "tag" parameter so that you know where it's called in the code. For example: checkHeapSize('constructor1');
2b) In order to check the heap limit, put the check in the loop and then run the check every 1000th iteration. This is done by adding a local variable called "i" (i.e. "integer i;"), incrementing it for each iteration, and then running the following code: if (math.mod(i, 1000) == 0) } { call the method }.
3) Review the debug logs to find the heap size to see if it's exceeding the limit. For issues with scheduled batches, testing in the Developer Console will run code synchronously and show the limit as 6 MB but the heap size limit for scheduled batches is the asynchronous limit of 12MB.
4) If heap size doesn't exceed the limit, repeat steps 1-3. If the limit is exceeded, the debug logs should point out the problematic section of code that will need to be fixed.
Example Problem Code
retryIds = new Set<String>();
for(Process_Error__c pe : [SELECT Id, Asset_Maintenance__c, AssetId__c, Error_Messages__c, No_of_Retries__c, Is_Successful__c FROM Process_Error__c WHERE Is_Successful__c = FALSE AND Max_Retries_Reached__c = FALSE]){
            ProcessErrorMap.put(pe.AssetId__c, pe);
                if (pe.Asset_Maintenance__c != null) {
To troubleshoot the code above, the checkHeapSize method can be called every 1000th iteration (per step 2b) in order to show the heap size growing and exceeding the limit. The problem above was that many objects were being added to a variable, in this case retryIds was adding objects and its size was growing too large for the heap limit. The heap size will change depending on the size of the objects so this code would need to be changed to avoid hitting the heap size limit when many records are processed.

promote demote