Fix "Apex Heap Size Too Large" in Salesforce

By Prit Sakhvala, Salesforce Developer · Updated July 2026

"Apex heap size too large" means your transaction held more than 6 MB of data in memory (12 MB async). The heap is everything your variables reference — query results, collections, strings, JSON, Blobs. The fix is holding less at once: SOQL for-loops, leaner field lists, chunked processing, or Batch Apex.

What the heap actually is

Every object your Apex code creates or references during a transaction lives on the heap: sObject lists from queries, maps you build, strings you concatenate, deserialized JSON structures, Blob contents. When the total exceeds the limit, Salesforce throws System.LimitException: Apex heap size too large — which, like all limit exceptions, cannot be caught.

Heap is shared across all namespaces in the transaction (like CPU time), so managed package allocations count against you too. See the full picture in governor limits explained.

The usual suspects

  1. Materializing big query results. List<Account> all = [SELECT ... FROM Account] on a large object loads every record and field into memory at once.
  2. Querying fields you don't use — especially long text areas and rich text fields, which can be 100 KB+ per record.
  3. String concatenation in loops. Each s += chunk creates a new string; building CSVs or HTML this way multiplies memory.
  4. JSON of large payloads. JSON.serialize/deserialize of big structures temporarily doubles the data (source + result both on heap).
  5. Blobs and attachments. Reading file bodies into Apex is the fastest way to blow 6 MB.
  6. Collections that never shrink — accumulating results across iterations instead of processing and clearing.

Finding heap hotspots in the debug log

Three techniques, cheapest first:

1. The limits summary

LIMIT_USAGE_FOR_NS|(default)| Maximum heap size: 5892411 out of 6000000 ******* CLOSE TO LIMIT

Confirms heap is the problem and how close you are. ForceLens's Limits tab shows this as a progress bar the moment the log opens.

2. Checkpoint logging

System.debug('Heap after query: ' + Limits.getHeapSize() + ' / ' + Limits.getLimitHeapSize()); // ... suspect operation ... System.debug('Heap after transform: ' + Limits.getHeapSize());

Bracket suspect operations with these and read the USER_DEBUG lines — the jump between checkpoints is your hotspot.

3. HEAP_ALLOCATE events

With ApexCode at FINEST, the log emits HEAP_ALLOCATE events with byte counts and line numbers. Extremely detailed but extremely verbose — combine with a class-scoped trace flag (see debug log levels) to keep the log under the 20 MB cap.

Fixes that work

Frequently asked questions

What is the Apex heap size limit?

6 MB per synchronous transaction, 12 MB for asynchronous (batch, future, queueable). Exceeding it throws an uncatchable limit exception.

What fills up the heap?

Query results held in lists, big strings, JSON serialization of large payloads, Blob/file bodies, and ever-growing collections — including allocations made by managed packages in your transaction.

How do I check heap usage?

Limits.getHeapSize() checkpoints logged with System.debug; the "Maximum heap size" line in LIMIT_USAGE_FOR_NS; and HEAP_ALLOCATE events at ApexCode FINEST.

How do I fix heap errors from large queries?

Use SOQL for-loops so records process in chunks, query fewer fields, or move to Batch Apex where each chunk gets a fresh 12 MB heap.

Spot heap pressure instantly

Open the log in ForceLens — the Limits tab shows heap against its budget as a progress bar, next to CPU, SOQL and DML. Free and local.

Add ForceLens to Chrome — Free