1

I am getting below error in my batch.

First error: Apex heap size too large: 12000354

Batch processes record more than 2 lakh (+edit: 200,000 for those not familiar with the Indian counting system). Here is the code:

global class OutputFileBatch implements Database.Batchable<sObject>, Database.Stateful{
    public Call_Plan_SCenario__c callPlanScenario{get;set;}
    public List<String> lstOfObjects ;
    public String str;
    public string[] fields;
    public string db_ObjectName;
    public Integer counter;

    public OutputFileBatch(Call_Plan_SCenario__c newObj,String objectName,Integer count){
         callPlanScenario=newObj;
         lstOfObjects = new List<String>();
         db_ObjectName = objectName;
         counter = count;
         system.debug('db_ObjectName-->'+db_ObjectName);
    }

    global Database.QueryLocator start(Database.BatchableContext BC){
       //String query = 'Select Id FROM Call_Plan_Scenario__c LIMIT 2';
       String fieldsreturned;
       str=Utilities.GetHeaders(db_ObjectName)+'\r\n';
       string[] fields=Utilities.GetQuery(db_ObjectName );
       String query = 'select '+ String.join(fields, ',') +' from '+ db_ObjectName;
       return database.getQueryLocator(query);
    }

    global void execute(Database.BatchableContext BC, List<sobject> scope){
        for(sObject rec : scope){
            str+=Utilities.GetRecord(rec,db_ObjectName);
            system.debug('**str**'+str);
            //str+='|'+'\n';
        }
    }

    global void finish(Database.BatchableContext BC){
        system.debug('**str**'+str);
        string nameOfFile = db_ObjectName;
        nameOfFile = nameOfFile.substring(0,nameOfFile.length()-3);
        system.debug(nameOfFile);

        Transient Attachment myAttachment = new Attachment();
        myAttachment.Body = Blob.valueOf(str);
        myAttachment.Name = nameOfFile +'.txt';
        myAttachment.ParentId = callPlanScenario.Id; 
        myAttachment.ContentType = 'text/csv';

        insert myAttachment;
        AsyncApexJob a = [SELECT Id, Status, NumberOfErrors, JobItemsProcessed, TotalJobItems, CreatedBy.Email FROM AsyncApexJob WHERE Id =:BC.getJobId()];

        if(a.NumberOfErrors ==0){
            // Database.executeBatch(new DeleteRecordsBatch(callPlanScenario,db_ObjectName,counter),1500);
        }  
    }    
}

Please can someone suggest what can we do to avoid this error.

6
  • I see you have debugs in your statement.Can you tell us which debug is coming and which is not?>
    – Samir
    Commented Feb 24, 2017 at 12:49
  • The size of data (in MB) that you are receiving is too large for the batch to handle, run the batch for one record or less number of records for one batch execution. Change the scope of batch to 1 if not already
    – d_k
    Commented Feb 24, 2017 at 12:50
  • @samir I am encountering problem here str+=Utilities.GetRecord(rec,db_ObjectName);
    – Jill_sfdc
    Commented Feb 24, 2017 at 12:51
  • Check out the Static Apex Limits - developer.salesforce.com/docs/atlas.en-us.apexcode.meta/…
    – d_k
    Commented Feb 24, 2017 at 12:55
  • As suggested by other, you should try decreasing your scope while executing your batch.
    – Samir
    Commented Feb 24, 2017 at 13:22

2 Answers 2

2

The essential problem here is that your batch finish() is taking the entire batch log and placing it into a single Attachment - but the accumulated log as well as Attachment bodies can be bigger than available async Heap size (12MB).

Within each execute(), you are appending to the Database.Stateful variable str and, as the number of records in the batch increases, you blow up heap

My suggestion is to create an Attachment for every x thousand objects within the execute() method. Or, you can be super clever and do this when the used heap is within 95% of available heap - write out the log to date, then clear the log.

Each attachment should be suffixed with a sequential identifier, starting at 0 (or 1)

In the finish() method, do the last log of any unlogged values in str. For small batches, this will be the only Attachment written

Your object denoted by callPlanScenario.Id would thus have one to n Attachments, a cumulative log.

5
  • What I understand from above is that if there are 200 batches and if I create attachment in execute there will be 200 attachment. Correct me if I am wrong anywhere.
    – Jill_sfdc
    Commented Feb 27, 2017 at 10:39
  • @Jill_sfdc - that is right; hence why I suggested deferring writing the attachment until the heap is within 95% of limits - otherwise you will have a lot of Attachments
    – cropredy
    Commented Feb 27, 2017 at 18:38
  • but I need one attachment only. Can't it be possible to do it otherwise.
    – Jill_sfdc
    Commented Feb 28, 2017 at 9:07
  • I tried creating attachment in execute method but no success till yet. Still I am facing issue.
    – Jill_sfdc
    Commented Feb 28, 2017 at 11:32
  • did you clear out value of str at beginning of every execute()?
    – cropredy
    Commented Feb 28, 2017 at 18:13
0

You are concatenating a string in a Stateful batch which eventually hits the heap size limit.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .