0
# JNA Memory Management
1
2
This document covers JNA's memory management system, including the Pointer and Memory classes, type-safe memory operations, and by-reference parameter passing.
3
4
## Core Imports
5
6
```java { .api }
7
import com.sun.jna.Pointer;
8
import com.sun.jna.Memory;
9
import com.sun.jna.ptr.*;
10
```
11
12
## Pointer Class - Base Memory Access
13
14
The `Pointer` class provides type-safe access to native memory locations:
15
16
```java { .api }
17
/**
18
* Represents a pointer to native memory with type-safe access methods
19
*/
20
public class Pointer {
21
/**
22
* Read byte value from memory
23
* @param offset Byte offset from pointer base
24
* @return Byte value at offset
25
*/
26
public byte getByte(long offset);
27
28
/**
29
* Write byte value to memory
30
* @param offset Byte offset from pointer base
31
* @param value Byte value to write
32
*/
33
public void setByte(long offset, byte value);
34
35
/**
36
* Read short value from memory (2 bytes)
37
* @param offset Byte offset from pointer base
38
* @return Short value at offset
39
*/
40
public short getShort(long offset);
41
42
/**
43
* Write short value to memory
44
* @param offset Byte offset from pointer base
45
* @param value Short value to write
46
*/
47
public void setShort(long offset, short value);
48
49
/**
50
* Read int value from memory (4 bytes)
51
* @param offset Byte offset from pointer base
52
* @return Int value at offset
53
*/
54
public int getInt(long offset);
55
56
/**
57
* Write int value to memory
58
* @param offset Byte offset from pointer base
59
* @param value Int value to write
60
*/
61
public void setInt(long offset, int value);
62
63
/**
64
* Read long value from memory (8 bytes)
65
* @param offset Byte offset from pointer base
66
* @return Long value at offset
67
*/
68
public long getLong(long offset);
69
70
/**
71
* Write long value to memory
72
* @param offset Byte offset from pointer base
73
* @param value Long value to write
74
*/
75
public void setLong(long offset, long value);
76
77
/**
78
* Read float value from memory (4 bytes)
79
* @param offset Byte offset from pointer base
80
* @return Float value at offset
81
*/
82
public float getFloat(long offset);
83
84
/**
85
* Write float value to memory
86
* @param offset Byte offset from pointer base
87
* @param value Float value to write
88
*/
89
public void setFloat(long offset, float value);
90
91
/**
92
* Read double value from memory (8 bytes)
93
* @param offset Byte offset from pointer base
94
* @return Double value at offset
95
*/
96
public double getDouble(long offset);
97
98
/**
99
* Write double value to memory
100
* @param offset Byte offset from pointer base
101
* @param value Double value to write
102
*/
103
public void setDouble(long offset, double value);
104
105
/**
106
* Read pointer value from memory
107
* @param offset Byte offset from pointer base
108
* @return Pointer value at offset (may be null)
109
*/
110
public Pointer getPointer(long offset);
111
112
/**
113
* Write pointer value to memory
114
* @param offset Byte offset from pointer base
115
* @param value Pointer value to write (may be null)
116
*/
117
public void setPointer(long offset, Pointer value);
118
119
/**
120
* Read null-terminated string from memory
121
* @param offset Byte offset from pointer base
122
* @param encoding Character encoding (e.g., "UTF-8", "UTF-16")
123
* @return String read from memory
124
*/
125
public String getString(long offset, String encoding);
126
127
/**
128
* Write null-terminated string to memory
129
* @param offset Byte offset from pointer base
130
* @param value String to write
131
* @param encoding Character encoding
132
*/
133
public void setString(long offset, String value, String encoding);
134
135
/**
136
* Create shared view of memory region
137
* @param offset Byte offset from pointer base
138
* @param size Size of shared region in bytes
139
* @return New pointer sharing memory region
140
*/
141
public Pointer share(long offset, long size);
142
143
/**
144
* Get NIO ByteBuffer view of memory
145
* @param offset Byte offset from pointer base
146
* @param length Size of buffer in bytes
147
* @return ByteBuffer backed by native memory
148
*/
149
public java.nio.ByteBuffer getByteBuffer(long offset, long length);
150
}
151
```
152
153
## Memory Class - Heap Allocation
154
155
The `Memory` class extends `Pointer` to provide malloc-based native memory allocation:
156
157
```java { .api }
158
/**
159
* Pointer to memory obtained from native heap with bounds checking
160
*/
161
public class Memory extends Pointer {
162
/**
163
* Allocate native memory block
164
* @param size Number of bytes to allocate
165
* @throws OutOfMemoryError if allocation fails
166
*/
167
public Memory(long size);
168
169
/**
170
* Get allocated memory size
171
* @return Size in bytes
172
*/
173
public long size();
174
175
/**
176
* Clear memory to zero
177
*/
178
public void clear();
179
180
/**
181
* Check if memory is still allocated
182
* @return true if memory is valid
183
*/
184
public boolean valid();
185
186
/**
187
* Create aligned memory view
188
* @param byteBoundary Alignment boundary (must be power of 2)
189
* @return New pointer aligned to boundary
190
*/
191
public Pointer align(int byteBoundary);
192
193
/**
194
* Explicitly dispose of memory
195
* Note: Memory is automatically freed by finalizer
196
*/
197
public void dispose();
198
199
// Static utility methods
200
201
/**
202
* Force cleanup of GC'd ByteBuffers
203
*/
204
public static void purge();
205
206
/**
207
* Dispose all allocated Memory objects
208
*/
209
public static void disposeAll();
210
}
211
```
212
213
## Basic Memory Operations
214
215
```java { .api }
216
// Allocate 1KB buffer
217
Memory buffer = new Memory(1024);
218
219
// Write primitive values
220
buffer.setInt(0, 42);
221
buffer.setFloat(4, 3.14f);
222
buffer.setLong(8, 123456789L);
223
224
// Read values back
225
int intVal = buffer.getInt(0); // 42
226
float floatVal = buffer.getFloat(4); // 3.14f
227
long longVal = buffer.getLong(8); // 123456789L
228
229
// String operations with encoding
230
buffer.setString(16, "Hello World", "UTF-8");
231
String text = buffer.getString(16, "UTF-8"); // "Hello World"
232
233
// Pointer operations
234
Memory subBuffer = new Memory(256);
235
buffer.setPointer(100, subBuffer);
236
Pointer retrieved = buffer.getPointer(100);
237
```
238
239
## Memory Sharing and Views
240
241
```java { .api }
242
// Create large buffer
243
Memory mainBuffer = new Memory(1000);
244
245
// Create shared views of different regions
246
Pointer header = mainBuffer.share(0, 100); // First 100 bytes
247
Pointer data = mainBuffer.share(100, 800); // Next 800 bytes
248
Pointer footer = mainBuffer.share(900, 100); // Last 100 bytes
249
250
// Write to shared regions
251
header.setInt(0, 0xDEADBEEF); // Magic number in header
252
data.setString(0, "payload", "UTF-8");
253
footer.setInt(0, 0xCAFEBABE); // Magic number in footer
254
255
// Changes are visible in main buffer
256
int magic = mainBuffer.getInt(0); // 0xDEADBEEF
257
String payload = mainBuffer.getString(100, "UTF-8"); // "payload"
258
```
259
260
## ByteBuffer Integration
261
262
```java { .api }
263
// Get NIO ByteBuffer view
264
Memory buffer = new Memory(512);
265
java.nio.ByteBuffer nio = buffer.getByteBuffer(0, 512);
266
267
// Use NIO operations
268
nio.putInt(42);
269
nio.putFloat(3.14f);
270
nio.flip();
271
272
// Read back via buffer methods
273
int value = buffer.getInt(0); // 42
274
float fval = buffer.getFloat(4); // 3.14f
275
```
276
277
## By-Reference Parameter Passing
278
279
JNA provides specialized classes for passing primitive values by reference:
280
281
```java { .api }
282
import com.sun.jna.ptr.*;
283
284
/**
285
* Base class for all by-reference types
286
*/
287
public abstract class ByReference extends PointerType {
288
/**
289
* Create with specified data size
290
* @param dataSize Size in bytes of referenced data
291
*/
292
protected ByReference(int dataSize);
293
}
294
295
/**
296
* Reference to a byte value (char* in C)
297
*/
298
public class ByteByReference extends ByReference {
299
public ByteByReference();
300
public ByteByReference(byte value);
301
302
/**
303
* Set the referenced byte value
304
* @param value New byte value
305
*/
306
public void setValue(byte value);
307
308
/**
309
* Get the referenced byte value
310
* @return Current byte value
311
*/
312
public byte getValue();
313
}
314
315
/**
316
* Reference to a short value (short* in C)
317
*/
318
public class ShortByReference extends ByReference {
319
public ShortByReference();
320
public ShortByReference(short value);
321
322
public void setValue(short value);
323
public short getValue();
324
}
325
326
/**
327
* Reference to an int value (int* in C)
328
*/
329
public class IntByReference extends ByReference {
330
public IntByReference();
331
public IntByReference(int value);
332
333
public void setValue(int value);
334
public int getValue();
335
}
336
337
/**
338
* Reference to a long value (long* in C)
339
*/
340
public class LongByReference extends ByReference {
341
public LongByReference();
342
public LongByReference(long value);
343
344
public void setValue(long value);
345
public long getValue();
346
}
347
348
/**
349
* Reference to a float value (float* in C)
350
*/
351
public class FloatByReference extends ByReference {
352
public FloatByReference();
353
public FloatByReference(float value);
354
355
public void setValue(float value);
356
public float getValue();
357
}
358
359
/**
360
* Reference to a double value (double* in C)
361
*/
362
public class DoubleByReference extends ByReference {
363
public DoubleByReference();
364
public DoubleByReference(double value);
365
366
public void setValue(double value);
367
public double getValue();
368
}
369
370
/**
371
* Reference to a NativeLong value (long* on platform)
372
*/
373
public class NativeLongByReference extends ByReference {
374
public NativeLongByReference();
375
public NativeLongByReference(NativeLong value);
376
377
public void setValue(NativeLong value);
378
public NativeLong getValue();
379
}
380
381
/**
382
* Reference to a Pointer value (void** in C)
383
*/
384
public class PointerByReference extends ByReference {
385
public PointerByReference();
386
public PointerByReference(Pointer value);
387
388
public void setValue(Pointer value);
389
public Pointer getValue();
390
}
391
```
392
393
## By-Reference Usage Examples
394
395
```java { .api }
396
// Define native function that modifies parameters
397
public interface MyLibrary extends Library {
398
MyLibrary INSTANCE = Native.loadLibrary("mylib", MyLibrary.class);
399
400
/**
401
* Function that increments an integer value
402
* void increment(int* value);
403
*/
404
void increment(IntByReference value);
405
406
/**
407
* Function that swaps two float values
408
* void swap_floats(float* a, float* b);
409
*/
410
void swap_floats(FloatByReference a, FloatByReference b);
411
412
/**
413
* Function that allocates memory and returns pointer
414
* int create_buffer(void** buffer, int size);
415
*/
416
int create_buffer(PointerByReference buffer, int size);
417
}
418
419
// Usage examples
420
IntByReference counter = new IntByReference(10);
421
MyLibrary.INSTANCE.increment(counter);
422
int newValue = counter.getValue(); // 11
423
424
FloatByReference a = new FloatByReference(1.0f);
425
FloatByReference b = new FloatByReference(2.0f);
426
MyLibrary.INSTANCE.swap_floats(a, b);
427
// Now a.getValue() == 2.0f and b.getValue() == 1.0f
428
429
PointerByReference bufferRef = new PointerByReference();
430
int result = MyLibrary.INSTANCE.create_buffer(bufferRef, 1024);
431
if (result == 0) {
432
Pointer buffer = bufferRef.getValue();
433
// Use the allocated buffer...
434
}
435
```
436
437
## Native String Handling
438
439
```java { .api }
440
/**
441
* Wide character string for Unicode support
442
*/
443
public final class WString implements CharSequence, Comparable<Object> {
444
/**
445
* Create wide string from regular string
446
* @param s String to convert
447
*/
448
public WString(String s);
449
450
/**
451
* Get string value
452
* @return String representation
453
*/
454
public String toString();
455
456
/**
457
* Get length in characters
458
* @return Number of characters
459
*/
460
public int length();
461
462
/**
463
* Get character at index
464
* @param index Character index
465
* @return Character at index
466
*/
467
public char charAt(int index);
468
469
/**
470
* Get subsequence
471
* @param start Start index (inclusive)
472
* @param end End index (exclusive)
473
* @return Character subsequence
474
*/
475
public CharSequence subSequence(int start, int end);
476
}
477
478
// String usage examples
479
Memory buffer = new Memory(256);
480
481
// ASCII strings
482
buffer.setString(0, "Hello", "ASCII");
483
String ascii = buffer.getString(0, "ASCII");
484
485
// UTF-8 strings
486
buffer.setString(50, "Hello 世界", "UTF-8");
487
String utf8 = buffer.getString(50, "UTF-8");
488
489
// Wide strings (platform-specific Unicode)
490
WString wide = new WString("Hello 世界");
491
// Pass to native function expecting wchar_t*
492
```
493
494
## String Array Support
495
496
```java { .api }
497
/**
498
* Array of strings in native memory
499
*/
500
public class StringArray extends Memory {
501
/**
502
* Create from String array using default encoding
503
* @param strings Array of strings
504
*/
505
public StringArray(String[] strings);
506
507
/**
508
* Create from String array with encoding choice
509
* @param strings Array of strings
510
* @param wide true for wide character encoding
511
*/
512
public StringArray(String[] strings, boolean wide);
513
514
/**
515
* Create from WString array
516
* @param strings Array of wide strings
517
*/
518
public StringArray(WString[] strings);
519
}
520
521
// Usage example
522
String[] args = {"program", "--verbose", "input.txt"};
523
StringArray argv = new StringArray(args);
524
525
// Pass to native function expecting char**
526
public interface System extends Library {
527
int exec(String program, StringArray argv);
528
}
529
```
530
531
## Memory Safety and Best Practices
532
533
```java { .api }
534
// 1. Always check buffer bounds
535
Memory buffer = new Memory(1024);
536
if (offset + dataSize <= buffer.size()) {
537
buffer.setInt(offset, value);
538
}
539
540
// 2. Use try-with-resources pattern for explicit cleanup
541
class ManagedMemory extends Memory implements AutoCloseable {
542
public ManagedMemory(long size) { super(size); }
543
544
@Override
545
public void close() {
546
dispose();
547
}
548
}
549
550
try (ManagedMemory buffer = new ManagedMemory(1024)) {
551
// Use buffer...
552
} // Automatically disposed
553
554
// 3. Validate pointer before use
555
public void safeRead(Pointer ptr, long offset) {
556
if (ptr != null && ptr != Pointer.NULL) {
557
int value = ptr.getInt(offset);
558
// Use value...
559
}
560
}
561
562
// 4. Handle encoding explicitly
563
String text = "Hello 世界";
564
buffer.setString(0, text, "UTF-8"); // Explicit encoding
565
String result = buffer.getString(0, "UTF-8");
566
567
// 5. Use sharing for structured access
568
Memory packet = new Memory(100);
569
Pointer header = packet.share(0, 20); // 20-byte header
570
Pointer payload = packet.share(20, 80); // 80-byte payload
571
```
572
573
## Advanced Memory Operations
574
575
```java { .api }
576
// Memory alignment for performance
577
Memory buffer = new Memory(1000);
578
Pointer aligned = buffer.align(16); // 16-byte aligned access
579
580
// Zero memory efficiently
581
buffer.clear(); // Zeros entire buffer
582
583
// Bulk copy operations
584
Memory src = new Memory(100);
585
Memory dst = new Memory(100);
586
// Fill source with data...
587
src.write(0, dst.getByteArray(0, 100), 0, 100);
588
589
// Get raw bytes for processing
590
byte[] rawData = buffer.getByteArray(0, (int)buffer.size());
591
// Process rawData...
592
buffer.write(0, rawData, 0, rawData.length);
593
```
594
595
## Error Handling
596
597
```java { .api }
598
try {
599
Memory buffer = new Memory(1024 * 1024 * 1024); // 1GB
600
// Use buffer...
601
} catch (OutOfMemoryError e) {
602
System.err.println("Failed to allocate native memory: " + e.getMessage());
603
}
604
605
// Check memory validity
606
Memory buffer = new Memory(1024);
607
if (buffer.valid()) {
608
buffer.setInt(0, 42);
609
} else {
610
throw new IllegalStateException("Buffer has been disposed");
611
}
612
```
613
614
This comprehensive memory management system provides safe, efficient access to native memory while maintaining Java's type safety and automatic memory management principles.