IJava |
JCOBridgeStream<T> ToStream<T>( FileAccess mode = FileAccess.Read, bool forceRawMemory = false ) where T : struct, new()
| JVM type | .NET type |
|---|---|
| boolean | bool |
| byte | byte |
| short | short |
| int | int |
| long | long |
| float | float |
| double | double |
| char | char |
Standard license — forceRawMemory has no effect. The stream operates on a local copy of the JVM array data. This is the same cost already paid when the array is obtained via ToArray, so no additional overhead is introduced. There are no constraints on JVM interaction or stream lifetime. Write-back to the JVM array is handled automatically on Dispose when the stream was opened with write access and at least one write was performed.
HPA license — forceRawMemory = . The JVM runtime may expose a direct pointer to the array storage or an internal copy, depending on the runtime implementation. In either case the GC runs normally and JVM interaction is unrestricted. The stream lifetime is not time-critical, but Dispose should be called promptly to release the JVM resource. Write-back is handled automatically on disposal.
HPA license — forceRawMemory = . The JVM is asked for a direct pointer to its internal array storage, avoiding any copy of the data into the managed heap. While the stream is alive the JVM garbage collector is suspended and no interaction with the JVM of any kind is permitted: no object allocation, no method calls, no blocking operations (I/O, locks, Thread.Sleep, etc.). Failing to respect these constraints may cause a deadlock or a JVM crash. Dispose is mandatory and must be invoked immediately after the memory operation completes. Always wrap the stream in a using block.
Performance considerations. Accessing JVM-resident memory through this stream is inherently slower on a per-element basis than accessing a managed .NET array, regardless of the license or forceRawMemory setting. The JVM allocator and the CLR managed heap occupy different physical memory regions; each access risks a TLB miss or a CPU cache miss because the hardware prefetcher has no prior knowledge of the JVM pages. By contrast, a managed array obtained via ToArray is warm in the CPU cache immediately after the copy and benefits from hardware prefetching and JIT bounds-check elimination on subsequent accesses. This stream is therefore most beneficial when the buffer is large enough that copying it would be prohibitive (hundreds of MB or more) and the access pattern is sparse or random — so that only a small fraction of elements are actually touched. For bulk sequential operations on the entire buffer, prefer JCOBridgeStream{T}.AsSpan followed by MemoryExtensions.SequenceEqual{T}(ReadOnlySpan{T}, ReadOnlySpan{T}) or a single-pass SIMD operation, which amortises the cache-miss cost over one contiguous scan.
// Standard license or HPA forceRawMemory = false — no constraints using var stream = javaArray.ToStream<double>(FileAccess.ReadWrite); double value = stream[0]; // HPA forceRawMemory = true — GC suspended, Dispose mandatory, no JVM calls using (var stream = javaArray.ToStream<double>(FileAccess.ReadWrite, forceRawMemory: true)) { // Only pure memory operations here — no JVM interaction of any kind. // Element-by-element access is slower than on a managed array; // use AsSpan() for bulk operations. bool eq = stream.AsSpan().SequenceEqual(otherSpan); } // GC resumes here; write-back is committed automatically