# capacity-heap

`software.visionary.cache:capacity-heap:2026.10.13` · https://codeberg.org/caching/capacity-heap

Heap-pressure cache capacity: bound a cache by the JVM's used heap

<code>RuntimeAvailableMemoryPercentage</code> is a <code>Capacity</code> exceeded when an <code>Insert</code> finds used heap above 75, 80, 85 or 90 percent of maximum heap.

## Rationale

**Why.** Values can differ in size by orders of magnitude, so a count of keys can be a poor stand-in for memory.

## Key Concepts

### Sampling heap pressure

**Role.** Each <code>Insert</code> compares used heap with the chosen <code>Percentage</code> of maximum heap, and <code>exceeded()</code> reports the result until an <code>Evict</code> clears it. <code>Percentage.getAsBoolean()</code> makes the comparison on demand.

**Pattern.** STRATEGY, OBSERVER

## How It Works

**Guarantees.** No public parameter takes null and no public method returns it, declared with contrax's <code>@PreCondition(IsNotNull.class)</code> and <code>@PostCondition(IsNotNull.class)</code>.

**Thread safety.** <code>update</code> and <code>exceeded()</code> may be called concurrently.

## Lane

**Purpose.** Giving memory back when the JVM's heap is under pressure.

**Alternative.** <code>capacity-fixed</code> for a predictable number of keys.

**When to avoid.** A hard memory ceiling: pressure is measured across the whole JVM, and an eviction does not promise memory comes back.

## Usage

Sampled on Insert, cleared by Evict

```java
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import software.visionary.cache.capacity.Capacity;
import software.visionary.cache.capacity.heap.RuntimeAvailableMemoryPercentage;
import software.visionary.cache.capacity.heap.RuntimeAvailableMemoryPercentage.Percentage;
import software.visionary.cache.events.Evict;
import software.visionary.cache.events.Insert;

Instant now = Instant.now();
Percentage limit = Percentage.SEVENTY_FIVE;
Capacity<String> capacity = new RuntimeAvailableMemoryPercentage<>(limit);

List<byte[]> ballast = new ArrayList<>();
while (!limit.getAsBoolean()) {
    ballast.add(new byte[1 << 20]);
}
System.out.println(capacity.exceeded());

capacity.update(new Insert.Key<>("a", now));
System.out.println(capacity.exceeded());

capacity.update(new Evict.Occurred<>("a", now));
System.out.println(capacity.exceeded() + " " + limit.getAsBoolean());

```

Output

```text
false
true
false true
```

## Dependencies

- `software.visionary:cache:2026.10.13` at Compile
- `software.visionary.contrax:processor:2026.10.13` at Processor
- `software.visionary:junit-closure:2026.09.17` at Testing

