6

I am wondering how to decide between heap size and processing time. This probably rather trivial but I have been researching for about an hour. The two images I used system.debug(Limits.getHeapSize());

They both are going over the same exact record in Salesforce.

The first image I did a soql for loop

for(variableType variableName : [soql query])

enter image description here

The second image I made a list with the soql query and then looped over the list.

List<sobject> myList = [soql query]; for(sobject variableName : myList)

enter image description here

From everything I have read online the first way I ran it is slower than the second, which I confirmed by using Limits.getCpuTime();. I am now wondering why in the first way I ran it, it shows a higher peak in heap size than the second way I ran it? From the Salesforce docs I read that the first way I ran it was supposed to be better for memory management and not hitting the heap size limit. Can anyone shed some light as to why the “better for not hitting heap size limit” way is causing my peak heap size to be greater? Am I understanding something wrong about when Salesforce checks heap size limits? Does heap size not matter during a soql for loop and only after the execution of it?

Thank you for any help, I am new to Apex and programming in general. Still trying to figure it all out and how to make these sort of design/architecture decisions.

4
  • What is the query/how many records is this query selecting? >200? Commented Sep 13, 2017 at 20:25
  • It is querying a custom object and a sub query within it and a where clause(which I will not include in the example [SELECT Id, (SELECT Name FROM Products__r) FROM Category__c] On Product__c, Category__c is a Lookup (Products is the child and category is the parent). It could exceed 200.
    – bemon
    Commented Sep 13, 2017 at 20:37
  • 2
    The difference is usually a matter of preference, although I went into some potential tangents that you may (or may not) find interesting here. In short, unless you're running up against a CPU or heap limit "wall", choose whichever you prefer, because they're very nearly identical in typical use cases.
    – sfdcfox
    Commented Sep 14, 2017 at 0:09
  • @sfdcfox thank you for your response and I did read through that many many times haha. At first it was not clicking for me but after I read it again after Daniel posted his answer yours then made sense. Just being new it sometimes clicks and sometimes takes a lot of reading and trying to understand for it to click. Thanks again!
    – bemon
    Commented Sep 14, 2017 at 14:42

1 Answer 1

7

I suspect you are measuring noise coming from the specific records being returned in the loop.

You looking at differences of between 1,901 and 1,849 bytes out of a total limit of 6,000,000 bytes.

Note the description for getHeapSize() from the docs (my emphasis):

Returns the approximate amount of memory (in bytes) that has been used for the heap.

As with measuring the CPU Time using getCpuTime() there can be variance from transaction to transaction. You didn't mention the specific values you were getting from the CPU time, but was the difference between the two approaches consistently significant?

Making meaningful measurements of CPU time in an environment where you share resources with others and don't control the load on the server or even know which specific server you are on is no trivial task. See Efficiency of List.size() > 0 vs. !List.isEmpty() for example.


From the SOQL For Loops Versus Standard SOQL Queries docs.

SOQL for loops differ from standard SOQL statements because of the method they use to retrieve sObjects. While the standard queries discussed in SOQL and SOSL Queries can retrieve either the count of a query or a number of object records, SOQL for loops retrieve all sObjects, using efficient chunking with calls to the query and queryMore methods of the SOAP API. Developers should always use a SOQL for loop to process query results that return many records, to avoid the limit on heap size.

If you think about it, this will keep the heap size down for larger result sets as it only needs to process a fixed block of records at a time. However, that doesn't come for free. There is a small overhead to manage the queryMore progression. The overhead could make it ever so slightly more expensive for smaller result sets. It will probably be negligible to any other processing you are doing.


Generally speaking, I find you usually have to make a trade off between heap usage and CPU time. You can use less CPU time, but you will need to use more memory to do so. E.g. storing pre-computed data structures

Aim first and foremost to make your code readable/maintainable while being mindful of the limits imposed by the system. If there is a demonstrable performance problem look to optimize it first using the approaches outlined in the best practices.

2
  • 1
    I have found virtually no variance in Heap usage, whatever the documentation may claim.
    – Adrian Larson
    Commented Sep 13, 2017 at 21:50
  • @AdrianLarson I suspect it is mostly noise related to the approximate measurement of heap usage. A SOQL For Loop won't be free from overhead, but we probably don't have the tools to measure it. Unless you have something hidden away in that library of yours :) Commented Sep 13, 2017 at 21:55

You must log in to answer this question.

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