ben-manes/caffeine · critical

Fail to realloc memory!\n

Error message

Fail to realloc memory!\n

What it means

A C runtime check in record_evict(): the eviction-sequence array evict_list is grown by doubling (evict_max_idx *= 2) with realloc whenever it fills; if realloc returns NULL — the doubling allocation failed — the tool prints this message and exits(1). Because the evict list grows with the number of evictions (often hundreds of millions in large traces), its size is the dominant allocation of the run, so this is effectively an out-of-memory error during long trace replays.

Source

Thrown at simulator/src/main/resources/com/github/benmanes/caffeine/cache/simulator/parser/lirs/lirs.c:303

    page_ptr->LIRS_prev->LIRS_next = page_ptr->LIRS_next;

  if (!page_ptr->LIRS_next)
    LRU_list_tail = page_ptr->LIRS_prev;
  else
    page_ptr->LIRS_next->LIRS_prev = page_ptr->LIRS_prev;

  page_ptr->LIRS_prev = page_ptr->LIRS_next = NULL;
  return TRUE;
}

/* record the evicted page from HIR queue */
void record_evict(unsigned long page_num) {
  if (evict_cur_idx >= (evict_max_idx-1)) {
    evict_max_idx *= 2;
    evict_list = realloc(evict_list,
                         evict_max_idx*sizeof(unsigned long));
    if (!evict_list) {
      fprintf(stderr, "Fail to realloc memory!\n");
      exit(1);
    }
  }

  evict_list[evict_cur_idx] = page_num;
  evict_cur_idx++;
}

/* remove a block from its the front of HIR resident list */
int remove_HIR_list(page_struct *HIR_block_ptr)
{
  if (!HIR_block_ptr)
    return FALSE;

  if (!HIR_block_ptr->HIR_rsd_prev)
    HIR_list_head = HIR_block_ptr->HIR_rsd_next;
  else
    HIR_block_ptr->HIR_rsd_prev->HIR_rsd_next = HIR_block_ptr->HIR_rsd_next;

View on GitHub (pinned to 9da6581ee3)

Solutions

  1. Give the process more memory (raise container limit, run on a bigger machine) — the list needs contiguous RAM of roughly the final eviction count × 8 bytes, plus a transient 2× copy
  2. Process the trace in smaller chunks if only statistics are needed
  3. If you only need the final hit/miss stats, compile a variant that skips record_evict()/print_evict_seq so the evict_list never grows
  4. On 64-bit hosts, confirm the binary is 64-bit (a 32-bit build caps out near 4 GB)
Defensive patterns

Strategy: validation

Validate before calling

# estimate eviction-log memory: 8 bytes per eviction, doubled during realloc
# ensure at least 3x headroom of the expected final size
est_evictions=$(wc -l < trace.dat)
need=$((est_evictions * 8 * 3))
avail=$(free -b | awk '/Mem:/{print $7}')
[ "$avail" -gt "$need" ] || { echo "realloc of evict_list will likely fail"; exit 1; }

Prevention

When it happens

Trigger: Replaying a long trace that produces more evictions than fit in memory: each doubling needs a fresh contiguous block of 2× size (peak usage ~3× during the copy); container memory caps; 32-bit address space exhaustion once evict_max_idx*sizeof(unsigned long) approaches 2-4 GB.

Common situations: Multi-GB production traces processed inside Docker/Kubernetes with low memory limits; CI runners with ~2-4 GB RAM; running the simulator's LIRS converter with eviction logging enabled on huge traces.

Related errors


AI-assisted analysis of ben-manes/caffeine@9da6581ee3 (2026-08-14). Data as JSON: /api/errors/acc02af32e0a4679. Report an issue: GitHub.