Using a radix tree to find case-insensitive matches in large files
time complexity

There is one troubling call in processCurrent that jumps out at me - the downcasing. I get the sense that sb becomes "big", so the nested inner loop for the linear scan seems like trouble. It's the sort of thing that can easily turn e.g. a linear algorithm into a quadratic one. I understand that case matters for correctness, but just humor me for a moment. Imagine  an alternate implementation that calls toLowerCase at file read time, destroying valuable information but allowing processCurrent to happen quicker. With such results in hand as a valuable hint, could you coax the current implementation to report results faster? As a simpler alternative, could we replace all comparisons in the current implementation with case-insensitive comparisons? Maybe downcase data when handing it to the radix tree library. The point is to avoid repeatedly downcasing a given character many thousands of times - we want to do localized work on our current focus rather than doing (ignored) global work.

memory complexity

There are a few large memory consumers such as storing Match hexOffsets, and storing charAndIndex tuples rather than generating them. Their cost is "just" linear with filesize, so maybe it's an acceptable tradeoff in the name of clarity, but you might think about what the code would look like if you deleted a large ancillary object (or made it smaller). Perhaps code that depended on the large object could get by within a smaller footprint? You're memory constrained and you want parallelism, so reducing memory by 2x would let you keep twice as many cores busy.

varying file sizes, and stragglers

The parallel mapping that invokes FileProcessor is very nice, it is simple and clear. But you complain about memory pressure, and I think your input files are of diverse sizes. This leads to two suggestions: consider viewing files as a series of fixed-length subproblems to work on, and consider throwing lots of tasks into a queue that a fixed number of worker bees draw from. Then you can size it so there's about N workers for N cores, each using about 1 / Nth of memory (either 1 / Nth of heap or 1 / Nth of cache, whichever matter more to your elapsed times). If the current code encounters a mix of files where the largest is, say, double the size of the smallest, then it's likely to be a straggler that impacts elapsed time while most of memory and most of cores are idle.

style

Instead of trie, it would have been helpful to me if you had written private val targetTrie, parallel with targetFile which is a nice informative identifier. It would be very helpful to write down pre- &amp; post-conditions that processCurrent maintains.