Every operation accepts an on-heap byte[] or any MemorySegment.
Whether the input is read in place or copied once is determined by what the native kernel returns, not by the binding.
Value- and offset-returning operations are always zero-copy, on heap or off-heap.
They are linked with the FFM critical option, so the JVM lets the kernel read the array in place with no thread-state transition.
This covers hash, byteSum, equal, compare, and the Hasher; codepoints (runes, decode); segmentation (words, graphemes, sentences, lineBreaks) and the separator-token splits (splitNewlines, splitWhitespaces, splitDelimiters); caseFold and normalize; and argSort / intersect.
Pointer-returning search copies an on-heap input once. indexOf / lastIndexOf / indexOfAny, the substring and byte-set splits (split, rsplit, splitAny), matches, uncasedMatches, and partition locate a match by pointer, and the JVM does not expose the address of pinned heap memory — so an on-heap byte[] (or a heap-backed MemorySegment, e.g. a Lucene BytesRef) is copied off-heap once before scanning.
That is one linear copy of the haystack per call, or per cursor() for the iterators, never per match.
Pass a native MemorySegment (an off-heap Arena, a direct ByteBuffer, an MMapDirectory slice, or a Spark Tungsten row) and these run fully in place with no copy.
| Input | Value / offset ops | Pointer search |
|---|---|---|
on-heap byte[] | zero-copy | copies once |
heap MemorySegment (e.g. BytesRef) | zero-copy | copies once |
native MemorySegment (off-heap) | zero-copy | zero-copy |
The copy exists only because the JVM hides the address of pinned heap memory.
For repeated pointer searches over the same large on-heap buffer, wrap it in a native MemorySegment once and reuse it.