6

I recently joined a new, very large, very old org that is in need of optimization. Previously they had a tendency to create brand new, separate utility classes for each new method being called from the main object handler. Each of these utility classes has a minimum of one List<Database.SaveResult> saveResults = new List<Database.SaveResult> scoped to the class, as well as other commonly re-used lists, variables, etc.

We all know that when you assign values to variables in memory, that takes up heap. A simple Execute Anonymous shows that multiple instances of new List<Database.SaveResult> takes up more heap than either declaring them without instantiation, or re-using the same list multiple times:

Multiple separate lists initiated:

System.debug(Limits.getHeapSize()); // 1055
List<Database.SaveResult> results = new List<Database.SaveResult>();
System.debug(Limits.getHeapSize()); // 1059
List<Database.SaveResult> saveResult2 = new List<Database.SaveResult>();
System.debug(Limits.getHeapSize()); // 1063
List<Database.SaveResult> saveResult3 = new List<Database.SaveResult>();
System.debug(Limits.getHeapSize()); // 1067
List<Database.SaveResult> saveResult4 = new List<Database.SaveResult>();
System.debug(Limits.getHeapSize()); // 1071

Declaration without instantiation:

System.debug(Limits.getHeapSize()); // 1055
List<Database.SaveResult> results;
System.debug(Limits.getHeapSize()); // 1055
List<Database.SaveResult> saveResult2;
System.debug(Limits.getHeapSize()); // 1055
List<Database.SaveResult> saveResult3;
System.debug(Limits.getHeapSize()); // 1055
List<Database.SaveResult> saveResult4;
System.debug(Limits.getHeapSize()); // 1055

Single List instantiated and re-used:

System.debug(Limits.getHeapSize()); // 1055
List<Database.SaveResult> results = new List<Database.SaveResult>();
System.debug(Limits.getHeapSize()); // 1059
results = new List<Database.SaveResult>();
System.debug(Limits.getHeapSize()); // 1059
results = new List<Database.SaveResult>();
System.debug(Limits.getHeapSize()); // 1059
results = new List<Database.SaveResult>();
System.debug(Limits.getHeapSize()); // 1059

An older post I found from 2018 suggests that you can free up heap by nulling or otherwise clearing the list after it is no longer in use: Heap size LIMIT

So, I have a few questions:

First, is the information in the post above considered a safe/acceptable method for freeing up heap? If I need to pass a list to another method for execution, but after I pass the list I don't need it anymore, I can freely clear it and that will give me back usable heap space? The post above says the items will stay in the heap somewhere until a HEAP_DEALLOCATION event, but I'm not clear on when a HEAP_DEALLOCATION event actually occurs.

Second, is a 'Singleton' approach considered more of a best practice in cases like this when a common list is going to be used throughout the program? For this specific example, I expect we will use List<Database.SaveResult> saveResults quite a few times during a transaction to capture the results of Database.update(listRecords,false) for error handling/logging.

1 Answer 1

6

First, is the information in the post above considered a safe/acceptable method for freeing up heap?

I'd hope so. I've used this for a very long time.

If I need to pass a list to another method for execution, but after I pass the list I don't need it anymore, I can freely clear it and that will give me back usable heap space?

Yes.

The post above says the items will stay in the heap somewhere until a HEAP_DEALLOCATION event, but I'm not clear on when a HEAP_DEALLOCATION event actually occurs.

It happens when the GC (Garbage Collector) runs. This happens periodically using an algorithm that isn't publicly documented (so, I have no idea). But it happens periodically based on some heuristics, and this presumably also triggers the LimitsException HEAP_LIMIT_EXCEEDED if, after GC runs, you are still over the limit (6MB, 12MB, or 36MB, depending on context).

Second, is a 'Singleton' approach considered more of a best practice in cases like this when a common list is going to be used throughout the program?

If they're different lists of save results, you'll probably want multiple objects. Just remember to free them as soon as they're no longer in use.

For this specific example, I expect we will use List<Database.SaveResult> saveResults quite a few times during a transaction to capture the results of Database.update(listRecords,false) for error handling/logging.

You should process the results as soon as possible, and discard the objects as soon as you no longer need them.

2
  • Hey fox - so to be clear, there's no difference in a single list that we overwrite with a new list on each Database.update versus just setting the old list to null once its not useful anymore? Jun 1, 2021 at 17:12
  • @MorganMarchese Right. As soon as you assign the new list, the old one gets bumped off, just as if we set the variable to null, so either approach is acceptable.
    – sfdcfox
    Jun 1, 2021 at 18:43

You must log in to answer this question.

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