So I have scenario where I need to process a bunch of blobs. I've tried to optimize my code and use Limits.getLimitHeapSize()
to detect prevent limit exceptions, by first breaking the attachments into groups so the SOQL query doesn't exceed the heap. Below is a simplified example of what that looks like.
However, I am finding Limits.getLimitHeapSize()
to be wildly inaccurate and thus not predicable.
Set<Id> batch = new Set<Id>();
Integer batchContentSize = 0;
for(Attachment attch : [SELECT BodyLength FROM Attachment WHERE ...]){
System.debug('Heap @ Start: ' + (Limits.getLimitHeapSize()-Limits.getHeapSize()));
//If we added the next image, we'd be at risk of hitting heap limit! Sync and reset
if(Limits.getHeapSize() + batchContentSize + attch.BodyLength*2 > maxHeapSize){
List<Attachment> attachments = [SELECT Body
FROM Attachment
WHERE Id IN :batchIds
ORDER BY BodyLength DESC];
System.debug('Heap Remaining After Query: ' + (Limits.getLimitHeapSize()-Limits.getHeapSize()));
//loop in revese & remove items from list to try and free up heap space ASAP
for(Integer i = attachments.size() - 1; i>=0; i--){
Attachment attchBody = attachments.remove(i);
String payload = EncodingUtil.base64Encode(attchBody.Body);
//do stuff with payload
foo(payload);
}
batchContentSize = 0;
batchIds = new Set<Id>();
}
batchContentSize += attch.BodyLength;
batch.add(attch.Id);
}
I have triple checked that I don't have any memory leaks due to bad scope (everything is localized to the smallest possible scope). However, either memory isn't being freed up or Limits.getLimitHeapSize() isn't calculating properly.
Example output of Debug:
Heap @ Start: 5399262
Heap Remaining After Query: 461459
Heap @ Start: 461364
Heap Remaining After Query: -4476045 //somehow exception doesn't even get thrown here...
batchIds
? I'd have thought it would only load the body for the last attachment you checked the BodyLength on.