0

I run the following code in the anonymous apex window. As you can see the accounts variable was declared inside an IF block. I output a debug outside of the IF block and the heap size was still showing the same number as it was inside the IF block.

My questions are:

  1. Why was the heap size not 'cleared' even though the accounts variable was not accessible anymore beyond the IF block?
  2. Why is the "Maximum heap size" limit shown as 0?
  3. Is setting the variable as null (to reduce the heap size?) a best practise?
System.debug(Limits.getHeapSize());
if (true) {
    List<Account> accounts = [SELECT Name FROM Account];
    System.debug(Limits.getHeapSize());
}
// System.debug(accounts);  Variable does not exist: accounts
System.debug(Limits.getHeapSize());

This is the output:

|USER_DEBUG|[1]|DEBUG|1047
|USER_DEBUG|[4]|DEBUG|4346177
|USER_DEBUG|[7]|DEBUG|4346177
|LIMIT_USAGE_FOR_NS|(default)|
  Maximum heap size: 0 out of 6000000

Notice that the heap size is still the same as previous (inside the IF block). If I set the accounts variable to null, the heap size is going back to close to the original size:

System.debug(Limits.getHeapSize());
if (true) {
    List<Account> accounts = [SELECT Name FROM Account];
    System.debug(Limits.getHeapSize());
    accounts = null;
}
System.debug(Limits.getHeapSize());

Output:

|USER_DEBUG|[1]|DEBUG|1049
|USER_DEBUG|[4]|DEBUG|4346177
|USER_DEBUG|[7]|DEBUG|1061
Maximum heap size: 0 out of 6000000

Thanks.

11
  • Since the Apex runtime is Java it doesn't surprise me that data lingers. Java uses garbage collection so data is only deleted when there are no (strong) references to it and the garbage collector is executed. How the Apex runtime handles variable declarations (and therefore the scope of references) comes down to the Apex "compiler", something only Salesforce Apex PMs and developers will have any details of. In addition, it is only these folks who will know if/when the garbage collector is explicitly invoked in Apex execution flows (it might be executed before getHeapSize, but I don't know).
    – Phil W
    Jan 6, 2021 at 8:24
  • My answer to your question #3 is a firm "no". There's no need for this, even if scopes are a little wider than they appear in the Apex code, the garbage collector will still deal with the data.
    – Phil W
    Jan 6, 2021 at 8:27
  • 3
    For #1 & #2: Heap size checks are performed according to certain heuristics, meaning they are not performed on evaluating each statement. Hence, the inconsistent numbers. Check this & this. Also, check this out.
    – arut
    Jan 6, 2021 at 8:45
  • 2
    If you are simply assigning a variable to null immediately before it goes out of scope this is generally, IMHO, unnecessary and simply adds more code to maintain and understand. Garbage will still be collected at some point. This null assign approach will only help in a very small number of cases where you have significant heap use - and in this case it is probably better to consider how to reduce over-all heap usage than to add such an assignment.
    – Phil W
    Jan 6, 2021 at 9:02
  • 1
    to confirm above, I wrote a unit test class that does asserts to verify that heap is reclaimed. The test is executed every day in 3 orgs over the span of 18 months; <1% of the time, the test fails and the only explanation is non-deterministic invocation of garbage collector.
    – cropredy
    Jan 6, 2021 at 23:00

0

Browse other questions tagged .