A stack is a place in the computer memory where all the variables that are declared and initialized before runtime are stored. The heap is the section of computer memory where all the variables created or initialized at runtime are stored. On the other hand, the heap is an area of memory used for dynamic memory allocation.
When you create objects in Apex code memory is allocated to store the objects. And that memory is allocated from the allocated heap. Think of it as a designated amount of memory you can use up in your Apex request.
Heap play an important role when your application runs, Bad code quality can consume the heap size badly and which impact the performance of your application
As you know heap is important to allocate the memory at runtime and hence we should be very careful while writing the code and must ensure to take care of heap size. If the heap size is huge, it will surely impact the performance of the application and the application will get slow.
Salesforce enforces an Apex Heap Size Limit of 6MB for synchronous transactions and 12MB for asynchronous transactions.
The "Apex heap size too large" error occurs when too much data is being stored in memory during processing. The limit depends on the type of execution (E.g. synchronous vs asynchronous calls) and the current value can be found in the Apex Developer's Guide.
It is important to review your code and follow best practices to ensure that the heap limit does not exceed the maximum. The below example shows the incorrect use of collections.
The List baseList, the value of SampleMap and the List tempList are pointing to the same memory address. As a result, the heap size doubles with each iteration of the loop.
public class HealsizeExample{
public static void testHeapSize(){
String str = 'aaaaa bbbbb ccccc ddddd eeeeee fffff hhhhh jjjjj kkkkk lllll mmmmm';
List<String> baseList = str.split(' ');
System.debug('This is baseList :'+baseList);
System.debug('This is baseList :'+baseList.size());
List<String> bigList = baseList;
system.debug('This is bigList :'+bigList);
System.debug('This is bigList :'+bigList.size());
Map<integer, List<String>> SampleMap = new Map<integer, List<String>>();
SampleMap.put(1, bigList);
system.debug('This is SampleMap :'+SampleMap);
System.debug('This is SampleMap :'+SampleMap.size());
for (integer i=0; i<50; i++) {
List<String> tempList = new List<String>();
tempList = SampleMap.get(1);
bigList.addAll(tempList);
}
system.debug('FINAL LIST SIZE IS '+bigList.size());
}
}
Solution-
public class heapCheckSuccess{
public static void myHeapTest(){
String tStr = 'aaaaa bbbbb ccccc ddddd eeeeee fffff ggggg 11111 22222 33333 44444';
List<String> baseList = tStr.split(' ');
Map<integer, List<String>> Sample = new Map<integer, List<String>>();
List<String> bigList = baseList;
Sample.put(1, bigList);
List<string> myList = new list<string>(); //Declare a new list
for (integer i=0; i<50; i++) {
List<String> tempList = new List<String>();
tempList = Sample.get(1);
system.debug('templist: ' + tempList.size());
system.debug(' bigList: ' + bigList.size());
myList.addall(tempList); //original code is bigList.addall(tempList);
}
system.debug('FINAL LIST SIZE OF bigList IS '+ bigList.size());
system.debug('myList IS '+mylist.size());
}
}
Best Practices to avoid Heap Size
Use the Transient Keyword
Use Limit Methods
Use heap limits methods in your Apex code to monitor/manage the heap during execution.
Limits.getHeapSize() - Returns the approximate amount of memory (in bytes) that has been used for the heap in the current context.
Limits.getLimitHeapSize() - Returns the total amount of memory (in bytes) that can be used for the heap in the current context.
Fetch only necessary Fields in the SOQL Query
Use SOQL For Loops
List accs = [SELECT Id, Name FROM Account];
for(Account a : accs){
System.debug(a.Name);
}
List accs = [SELECT Id, Name FROM Account];
for(Account a : accs){
System.debug(a.Name);
}
Solution
for(Account a : [SELECT Id, Name FROM Account]){
System.debug(a.Name);
}
for(Account a : [SELECT Id, Name FROM Account]){
System.debug(a.Name);
}
Switching to Batch Apex increased the heap limit to 12000000 bytes. Also, by setting the scope to 1 only one attachment was processed at a time.
Don't use class-level variables to store a large amount of data.
Run Future Methods with Higher Limits (Pilot)
@future(limits='2xHeap')
public static void myFutureMethod() {
// Your code here
}