CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-net-java-dev-jna--jna

Java Native Access (JNA) provides Java programs easy access to native shared libraries without writing anything but Java code - no JNI or native code is required.

Pending
Overview
Eval results
Files

memory-management.mddocs/

JNA Memory Management

This document covers JNA's memory management system, including the Pointer and Memory classes, type-safe memory operations, and by-reference parameter passing.

Core Imports

import com.sun.jna.Pointer;
import com.sun.jna.Memory; 
import com.sun.jna.ptr.*;

Pointer Class - Base Memory Access

The Pointer class provides type-safe access to native memory locations:

/**
 * Represents a pointer to native memory with type-safe access methods
 */
public class Pointer {
    /**
     * Read byte value from memory
     * @param offset Byte offset from pointer base
     * @return Byte value at offset
     */
    public byte getByte(long offset);
    
    /**
     * Write byte value to memory
     * @param offset Byte offset from pointer base  
     * @param value Byte value to write
     */
    public void setByte(long offset, byte value);
    
    /**
     * Read short value from memory (2 bytes)
     * @param offset Byte offset from pointer base
     * @return Short value at offset
     */
    public short getShort(long offset);
    
    /**
     * Write short value to memory
     * @param offset Byte offset from pointer base
     * @param value Short value to write
     */
    public void setShort(long offset, short value);
    
    /**
     * Read int value from memory (4 bytes)
     * @param offset Byte offset from pointer base
     * @return Int value at offset
     */
    public int getInt(long offset);
    
    /**
     * Write int value to memory
     * @param offset Byte offset from pointer base
     * @param value Int value to write
     */
    public void setInt(long offset, int value);
    
    /**
     * Read long value from memory (8 bytes)
     * @param offset Byte offset from pointer base
     * @return Long value at offset
     */
    public long getLong(long offset);
    
    /**
     * Write long value to memory
     * @param offset Byte offset from pointer base
     * @param value Long value to write
     */
    public void setLong(long offset, long value);
    
    /**
     * Read float value from memory (4 bytes)
     * @param offset Byte offset from pointer base
     * @return Float value at offset
     */
    public float getFloat(long offset);
    
    /**
     * Write float value to memory
     * @param offset Byte offset from pointer base
     * @param value Float value to write
     */
    public void setFloat(long offset, float value);
    
    /**
     * Read double value from memory (8 bytes)
     * @param offset Byte offset from pointer base
     * @return Double value at offset
     */
    public double getDouble(long offset);
    
    /**
     * Write double value to memory
     * @param offset Byte offset from pointer base
     * @param value Double value to write
     */
    public void setDouble(long offset, double value);
    
    /**
     * Read pointer value from memory
     * @param offset Byte offset from pointer base
     * @return Pointer value at offset (may be null)
     */
    public Pointer getPointer(long offset);
    
    /**
     * Write pointer value to memory
     * @param offset Byte offset from pointer base
     * @param value Pointer value to write (may be null)
     */
    public void setPointer(long offset, Pointer value);
    
    /**
     * Read null-terminated string from memory
     * @param offset Byte offset from pointer base
     * @param encoding Character encoding (e.g., "UTF-8", "UTF-16")
     * @return String read from memory
     */
    public String getString(long offset, String encoding);
    
    /**
     * Write null-terminated string to memory
     * @param offset Byte offset from pointer base
     * @param value String to write
     * @param encoding Character encoding
     */
    public void setString(long offset, String value, String encoding);
    
    /**
     * Create shared view of memory region
     * @param offset Byte offset from pointer base
     * @param size Size of shared region in bytes
     * @return New pointer sharing memory region
     */
    public Pointer share(long offset, long size);
    
    /**
     * Get NIO ByteBuffer view of memory
     * @param offset Byte offset from pointer base  
     * @param length Size of buffer in bytes
     * @return ByteBuffer backed by native memory
     */
    public java.nio.ByteBuffer getByteBuffer(long offset, long length);
}

Memory Class - Heap Allocation

The Memory class extends Pointer to provide malloc-based native memory allocation:

/**
 * Pointer to memory obtained from native heap with bounds checking
 */
public class Memory extends Pointer {
    /**
     * Allocate native memory block
     * @param size Number of bytes to allocate
     * @throws OutOfMemoryError if allocation fails
     */
    public Memory(long size);
    
    /**
     * Get allocated memory size
     * @return Size in bytes
     */
    public long size();
    
    /**
     * Clear memory to zero
     */
    public void clear();
    
    /**
     * Check if memory is still allocated
     * @return true if memory is valid
     */
    public boolean valid();
    
    /**
     * Create aligned memory view
     * @param byteBoundary Alignment boundary (must be power of 2)
     * @return New pointer aligned to boundary
     */
    public Pointer align(int byteBoundary);
    
    /**
     * Explicitly dispose of memory
     * Note: Memory is automatically freed by finalizer
     */
    public void dispose();
    
    // Static utility methods
    
    /**
     * Force cleanup of GC'd ByteBuffers
     */
    public static void purge();
    
    /**
     * Dispose all allocated Memory objects
     */
    public static void disposeAll();
}

Basic Memory Operations

// Allocate 1KB buffer
Memory buffer = new Memory(1024);

// Write primitive values
buffer.setInt(0, 42);
buffer.setFloat(4, 3.14f);
buffer.setLong(8, 123456789L);

// Read values back
int intVal = buffer.getInt(0);      // 42
float floatVal = buffer.getFloat(4); // 3.14f  
long longVal = buffer.getLong(8);   // 123456789L

// String operations with encoding
buffer.setString(16, "Hello World", "UTF-8");
String text = buffer.getString(16, "UTF-8"); // "Hello World"

// Pointer operations
Memory subBuffer = new Memory(256);
buffer.setPointer(100, subBuffer);
Pointer retrieved = buffer.getPointer(100);

Memory Sharing and Views

// Create large buffer
Memory mainBuffer = new Memory(1000);

// Create shared views of different regions
Pointer header = mainBuffer.share(0, 100);    // First 100 bytes
Pointer data = mainBuffer.share(100, 800);    // Next 800 bytes
Pointer footer = mainBuffer.share(900, 100);  // Last 100 bytes

// Write to shared regions
header.setInt(0, 0xDEADBEEF);  // Magic number in header
data.setString(0, "payload", "UTF-8");
footer.setInt(0, 0xCAFEBABE); // Magic number in footer

// Changes are visible in main buffer
int magic = mainBuffer.getInt(0);      // 0xDEADBEEF
String payload = mainBuffer.getString(100, "UTF-8"); // "payload"

ByteBuffer Integration

// Get NIO ByteBuffer view
Memory buffer = new Memory(512);
java.nio.ByteBuffer nio = buffer.getByteBuffer(0, 512);

// Use NIO operations
nio.putInt(42);
nio.putFloat(3.14f);
nio.flip();

// Read back via buffer methods
int value = buffer.getInt(0);       // 42
float fval = buffer.getFloat(4);    // 3.14f

By-Reference Parameter Passing

JNA provides specialized classes for passing primitive values by reference:

import com.sun.jna.ptr.*;

/**
 * Base class for all by-reference types
 */
public abstract class ByReference extends PointerType {
    /**
     * Create with specified data size
     * @param dataSize Size in bytes of referenced data
     */
    protected ByReference(int dataSize);
}

/**
 * Reference to a byte value (char* in C)
 */
public class ByteByReference extends ByReference {
    public ByteByReference();
    public ByteByReference(byte value);
    
    /**
     * Set the referenced byte value
     * @param value New byte value
     */
    public void setValue(byte value);
    
    /**
     * Get the referenced byte value
     * @return Current byte value
     */
    public byte getValue();
}

/**
 * Reference to a short value (short* in C)
 */
public class ShortByReference extends ByReference {
    public ShortByReference();
    public ShortByReference(short value);
    
    public void setValue(short value);
    public short getValue();
}

/**
 * Reference to an int value (int* in C)
 */
public class IntByReference extends ByReference {
    public IntByReference();
    public IntByReference(int value);
    
    public void setValue(int value);
    public int getValue();
}

/**
 * Reference to a long value (long* in C)
 */
public class LongByReference extends ByReference {
    public LongByReference();
    public LongByReference(long value);
    
    public void setValue(long value);
    public long getValue();
}

/**
 * Reference to a float value (float* in C)
 */
public class FloatByReference extends ByReference {
    public FloatByReference();
    public FloatByReference(float value);
    
    public void setValue(float value);
    public float getValue();
}

/**
 * Reference to a double value (double* in C)
 */
public class DoubleByReference extends ByReference {
    public DoubleByReference();
    public DoubleByReference(double value);
    
    public void setValue(double value);
    public double getValue();
}

/**
 * Reference to a NativeLong value (long* on platform)
 */
public class NativeLongByReference extends ByReference {
    public NativeLongByReference();
    public NativeLongByReference(NativeLong value);
    
    public void setValue(NativeLong value);
    public NativeLong getValue();
}

/**
 * Reference to a Pointer value (void** in C)
 */
public class PointerByReference extends ByReference {
    public PointerByReference();
    public PointerByReference(Pointer value);
    
    public void setValue(Pointer value);
    public Pointer getValue();
}

By-Reference Usage Examples

// Define native function that modifies parameters
public interface MyLibrary extends Library {
    MyLibrary INSTANCE = Native.loadLibrary("mylib", MyLibrary.class);
    
    /**
     * Function that increments an integer value
     * void increment(int* value);
     */
    void increment(IntByReference value);
    
    /**
     * Function that swaps two float values
     * void swap_floats(float* a, float* b);
     */
    void swap_floats(FloatByReference a, FloatByReference b);
    
    /**
     * Function that allocates memory and returns pointer
     * int create_buffer(void** buffer, int size);
     */
    int create_buffer(PointerByReference buffer, int size);
}

// Usage examples
IntByReference counter = new IntByReference(10);
MyLibrary.INSTANCE.increment(counter);
int newValue = counter.getValue(); // 11

FloatByReference a = new FloatByReference(1.0f);
FloatByReference b = new FloatByReference(2.0f);
MyLibrary.INSTANCE.swap_floats(a, b);
// Now a.getValue() == 2.0f and b.getValue() == 1.0f

PointerByReference bufferRef = new PointerByReference();
int result = MyLibrary.INSTANCE.create_buffer(bufferRef, 1024);
if (result == 0) {
    Pointer buffer = bufferRef.getValue();
    // Use the allocated buffer...
}

Native String Handling

/**
 * Wide character string for Unicode support
 */
public final class WString implements CharSequence, Comparable<Object> {
    /**
     * Create wide string from regular string
     * @param s String to convert
     */
    public WString(String s);
    
    /**
     * Get string value
     * @return String representation
     */
    public String toString();
    
    /**
     * Get length in characters
     * @return Number of characters
     */
    public int length();
    
    /**
     * Get character at index
     * @param index Character index
     * @return Character at index
     */
    public char charAt(int index);
    
    /**
     * Get subsequence
     * @param start Start index (inclusive)
     * @param end End index (exclusive)
     * @return Character subsequence
     */
    public CharSequence subSequence(int start, int end);
}

// String usage examples
Memory buffer = new Memory(256);

// ASCII strings
buffer.setString(0, "Hello", "ASCII");
String ascii = buffer.getString(0, "ASCII");

// UTF-8 strings  
buffer.setString(50, "Hello 世界", "UTF-8");
String utf8 = buffer.getString(50, "UTF-8");

// Wide strings (platform-specific Unicode)
WString wide = new WString("Hello 世界");
// Pass to native function expecting wchar_t*

String Array Support

/**
 * Array of strings in native memory
 */
public class StringArray extends Memory {
    /**
     * Create from String array using default encoding
     * @param strings Array of strings
     */
    public StringArray(String[] strings);
    
    /**
     * Create from String array with encoding choice
     * @param strings Array of strings
     * @param wide true for wide character encoding
     */
    public StringArray(String[] strings, boolean wide);
    
    /**
     * Create from WString array
     * @param strings Array of wide strings
     */
    public StringArray(WString[] strings);
}

// Usage example
String[] args = {"program", "--verbose", "input.txt"};
StringArray argv = new StringArray(args);

// Pass to native function expecting char**
public interface System extends Library {
    int exec(String program, StringArray argv);
}

Memory Safety and Best Practices

// 1. Always check buffer bounds
Memory buffer = new Memory(1024);
if (offset + dataSize <= buffer.size()) {
    buffer.setInt(offset, value);
}

// 2. Use try-with-resources pattern for explicit cleanup
class ManagedMemory extends Memory implements AutoCloseable {
    public ManagedMemory(long size) { super(size); }
    
    @Override
    public void close() {
        dispose();
    }
}

try (ManagedMemory buffer = new ManagedMemory(1024)) {
    // Use buffer...
} // Automatically disposed

// 3. Validate pointer before use
public void safeRead(Pointer ptr, long offset) {
    if (ptr != null && ptr != Pointer.NULL) {
        int value = ptr.getInt(offset);
        // Use value...
    }
}

// 4. Handle encoding explicitly
String text = "Hello 世界";
buffer.setString(0, text, "UTF-8");  // Explicit encoding
String result = buffer.getString(0, "UTF-8");

// 5. Use sharing for structured access
Memory packet = new Memory(100);
Pointer header = packet.share(0, 20);   // 20-byte header
Pointer payload = packet.share(20, 80); // 80-byte payload

Advanced Memory Operations

// Memory alignment for performance
Memory buffer = new Memory(1000);
Pointer aligned = buffer.align(16); // 16-byte aligned access

// Zero memory efficiently  
buffer.clear(); // Zeros entire buffer

// Bulk copy operations
Memory src = new Memory(100);
Memory dst = new Memory(100);
// Fill source with data...
src.write(0, dst.getByteArray(0, 100), 0, 100);

// Get raw bytes for processing
byte[] rawData = buffer.getByteArray(0, (int)buffer.size());
// Process rawData...
buffer.write(0, rawData, 0, rawData.length);

Error Handling

try {
    Memory buffer = new Memory(1024 * 1024 * 1024); // 1GB
    // Use buffer...
} catch (OutOfMemoryError e) {
    System.err.println("Failed to allocate native memory: " + e.getMessage());
}

// Check memory validity
Memory buffer = new Memory(1024);
if (buffer.valid()) {
    buffer.setInt(0, 42);
} else {
    throw new IllegalStateException("Buffer has been disposed");
}

This comprehensive memory management system provides safe, efficient access to native memory while maintaining Java's type safety and automatic memory management principles.

Install with Tessl CLI

npx tessl i tessl/maven-net-java-dev-jna--jna

docs

index.md

memory-management.md

ptr-package.md

structures-types.md

windows.md

tile.json