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.

  • I see you have debugs in your statement.Can you tell us which debug is coming and which is not?> – Samir Feb 24 '17 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 Feb 24 '17 at 12:50
  • @samir I am encountering problem here str+=Utilities.GetRecord(rec,db_ObjectName); – Jill_sfdc Feb 24 '17 at 12:51
  • Check out the Static Apex Limits - developer.salesforce.com/docs/atlas.en-us.apexcode.meta/… – d_k Feb 24 '17 at 12:55
  • As suggested by other, you should try decreasing your scope while executing your batch. – Samir Feb 24 '17 at 13:22
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.

| improve this answer | |
  • 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 Feb 27 '17 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 Feb 27 '17 at 18:38
  • but I need one attachment only. Can't it be possible to do it otherwise. – Jill_sfdc Feb 28 '17 at 9:07
  • I tried creating attachment in execute method but no success till yet. Still I am facing issue. – Jill_sfdc Feb 28 '17 at 11:32
  • did you clear out value of str at beginning of every execute()? – cropredy Feb 28 '17 at 18:13
0

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

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.