All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sun.jna.Memory Maven / Gradle / Ivy

There is a newer version: 1.2.2.1-jre17
Show newest version
/*
 * The contents of this file is dual-licensed under 2
 * alternative Open Source/Free licenses: LGPL 2.1 or later and
 * Apache License 2.0. (starting with JNA version 4.0.0).
 *
 * You can freely decide which license you want to apply to
 * the project.
 *
 * You may obtain a copy of the LGPL License at:
 *
 * http://www.gnu.org/licenses/licenses.html
 *
 * A copy is also included in the downloadable source code package
 * containing JNA, in file "LGPL2.1".
 *
 * You may obtain a copy of the Apache License at:
 *
 * http://www.apache.org/licenses/
 *
 * A copy is also included in the downloadable source code package
 * containing JNA, in file "AL2.0".
 */
package com.sun.jna;

import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.nio.ByteBuffer;
import java.util.ArrayList;

/**
 * A Pointer to memory obtained from the native heap via a
 * call to malloc.
 *
 * 

In some cases it might be necessary to use memory obtained from * malloc. For example, Memory helps * accomplish the following idiom: *

 *        void *buf = malloc(BUF_LEN * sizeof(char));
 *        call_some_function(buf);
 *        free(buf);
 * 
* *

The {@link #finalize} method will free allocated memory when * this object is no longer referenced. * * @author Sheng Liang, originator * @author Todd Fast, suitability modifications * @author Timothy Wall * @see Pointer */ public class Memory extends Pointer { private static ReferenceQueue QUEUE = new ReferenceQueue(); private static LinkedReference HEAD; // the head of the doubly linked list used for instance tracking /** * Keep track of all allocated memory so we can dispose of it before * unloading. This is done using a doubly linked list to enable fast * removal of tracked instances. */ private static class LinkedReference extends WeakReference { private LinkedReference next; private LinkedReference prev; private LinkedReference(Memory referent) { super(referent, QUEUE); } /** * Add the given {@code instance} to the instance tracking. * * @param instance the instance to track */ static LinkedReference track(Memory instance) { // use a different lock here to allow the finialzier to unlink elements too synchronized (QUEUE) { LinkedReference stale; // handle stale references here to avoid GC overheating when memory is limited while ((stale = (LinkedReference) QUEUE.poll()) != null) { stale.unlink(); } } // keep object allocation outside the syncronized block LinkedReference entry = new LinkedReference(instance); synchronized (LinkedReference.class) { if (HEAD != null) { entry.next = HEAD; HEAD = HEAD.prev = entry; } else { HEAD = entry; } } return entry; } /** * Remove the related instance from tracking and update the linked list. */ private void unlink() { synchronized (LinkedReference.class) { LinkedReference next; if (HEAD != this) { if (this.prev == null) { // this entry was detached before, e.g. disposeAll was called and finalizers are running now return; } next = this.prev.next = this.next; } else { next = HEAD = HEAD.next; } if (next != null) { next.prev = this.prev; } // set prev to null to detect detached entries this.prev = null; } } } private static final WeakMemoryHolder buffers = new WeakMemoryHolder(); /** Force cleanup of memory that has associated NIO Buffers which have been GC'd. */ public static void purge() { buffers.clean(); } /** Dispose of all allocated memory. */ public static void disposeAll() { synchronized (LinkedReference.class) { LinkedReference entry; while ((entry = HEAD) != null) { Memory memory = HEAD.get(); if (memory != null) { // dispose does the unlink call internal memory.dispose(); } else { HEAD.unlink(); } if (HEAD == entry) { throw new IllegalStateException("the HEAD did not change"); } } } synchronized (QUEUE) { LinkedReference stale; // try to release as mutch memory as possible while ((stale = (LinkedReference) QUEUE.poll()) != null) { stale.unlink(); } } } /** * Unit-testing only, ensure the doubly linked list is in a good shape. * * @return the number of tracked instances */ static int integrityCheck() { synchronized (LinkedReference.class) { if (HEAD == null) { return 0; } ArrayList entries = new ArrayList(); LinkedReference entry = HEAD; while (entry != null) { entries.add(entry); entry = entry.next; } int index = entries.size() - 1; entry = entries.get(index); while (entry != null) { if (entries.get(index) != entry) { throw new IllegalStateException(entries.get(index) + " vs. " + entry + " at index " + index); } entry = entry.prev; index--; } return entries.size(); } } private final LinkedReference reference; // used to track the instance protected long size; // Size of the malloc'ed space /** Provide a view into the original memory. Keeps an implicit reference * to the original to prevent GC. */ private class SharedMemory extends Memory { public SharedMemory(long offset, long size) { this.size = size; this.peer = Memory.this.peer + offset; } /** No need to free memory. */ @Override protected synchronized void dispose() { this.peer = 0; } /** Pass bounds check to parent. */ @Override protected void boundsCheck(long off, long sz) { Memory.this.boundsCheck(this.peer - Memory.this.peer + off, sz); } @Override public String toString() { return super.toString() + " (shared from " + Memory.this.toString() + ")"; } } /** * Allocate space in the native heap via a call to C's malloc. * * @param size number of bytes of space to allocate */ public Memory(long size) { this.size = size; if (size <= 0) { throw new IllegalArgumentException("Allocation size must be greater than zero"); } peer = malloc(size); if (peer == 0) throw new OutOfMemoryError("Cannot allocate " + size + " bytes"); reference = LinkedReference.track(this); } protected Memory() { super(); reference = null; } /** Provide a view of this memory using the given offset as the base address. The * returned {@link Pointer} will have a size equal to that of the original * minus the offset. * @throws IndexOutOfBoundsException if the requested memory is outside * the allocated bounds. */ @Override public Pointer share(long offset) { return share(offset, size() - offset); } /** Provide a view of this memory using the given offset as the base * address, bounds-limited with the given size. Maintains a reference to * the original {@link Memory} object to avoid GC as long as the shared * memory is referenced. * @throws IndexOutOfBoundsException if the requested memory is outside * the allocated bounds. */ @Override public Pointer share(long offset, long sz) { boundsCheck(offset, sz); return new SharedMemory(offset, sz); } /** Provide a view onto this structure with the given alignment. * @param byteBoundary Align memory to this number of bytes; should be a * power of two. * @throws IndexOutOfBoundsException if the requested alignment can * not be met. * @throws IllegalArgumentException if the requested alignment is not * a positive power of two. */ public Memory align(int byteBoundary) { if (byteBoundary <= 0) { throw new IllegalArgumentException("Byte boundary must be positive: " + byteBoundary); } for (int i=0;i < 32;i++) { if (byteBoundary == (1< size) { String msg = "Bounds exceeds available space : size=" + size + ", offset=" + (off + sz); throw new IndexOutOfBoundsException(msg); } } ////////////////////////////////////////////////////////////////////////// // Raw read methods ////////////////////////////////////////////////////////////////////////// /** * Indirect the native pointer to malloc space, a la * Pointer.read. But this method performs a bounds * checks to ensure that the indirection does not cause memory outside the * malloced space to be accessed. * * @see Pointer#read(long,byte[],int,int) */ @Override public void read(long bOff, byte[] buf, int index, int length) { boundsCheck(bOff, length * 1L); super.read(bOff, buf, index, length); } /** * Indirect the native pointer to malloc space, a la * Pointer.read. But this method performs a bounds * checks to ensure that the indirection does not cause memory outside the * malloced space to be accessed. * * @see Pointer#read(long,short[],int,int) */ @Override public void read(long bOff, short[] buf, int index, int length) { boundsCheck(bOff, length * 2L); super.read(bOff, buf, index, length); } /** * Indirect the native pointer to malloc space, a la * Pointer.read. But this method performs a bounds * checks to ensure that the indirection does not cause memory outside the * malloced space to be accessed. * * @see Pointer#read(long,char[],int,int) */ @Override public void read(long bOff, char[] buf, int index, int length) { boundsCheck(bOff, length * Native.WCHAR_SIZE); super.read(bOff, buf, index, length); } /** * Indirect the native pointer to malloc space, a la * Pointer.read. But this method performs a bounds * checks to ensure that the indirection does not cause memory outside the * malloced space to be accessed. * * @see Pointer#read(long,int[],int,int) */ @Override public void read(long bOff, int[] buf, int index, int length) { boundsCheck(bOff, length * 4L); super.read(bOff, buf, index, length); } /** * Indirect the native pointer to malloc space, a la * Pointer.read. But this method performs a bounds * checks to ensure that the indirection does not cause memory outside the * malloced space to be accessed. * * @see Pointer#read(long,long[],int,int) */ @Override public void read(long bOff, long[] buf, int index, int length) { boundsCheck(bOff, length * 8L); super.read(bOff, buf, index, length); } /** * Indirect the native pointer to malloc space, a la * Pointer.read. But this method performs a bounds * checks to ensure that the indirection does not cause memory outside the * malloced space to be accessed. * * @see Pointer#read(long,float[],int,int) */ @Override public void read(long bOff, float[] buf, int index, int length) { boundsCheck(bOff, length * 4L); super.read(bOff, buf, index, length); } /** * Indirect the native pointer to malloc space, a la * Pointer.read. But this method performs a bounds checks to * ensure that the indirection does not cause memory outside the * malloced space to be accessed. * * @see Pointer#read(long,double[],int,int) */ @Override public void read(long bOff, double[] buf, int index, int length) { boundsCheck(bOff, length * 8L); super.read(bOff, buf, index, length); } /** * Indirect the native pointer to malloc space, a la * Pointer.read. But this method performs a bounds checks to * ensure that the indirection does not cause memory outside the * malloced space to be accessed. * * @see Pointer#read(long,Pointer[],int,int) */ @Override public void read(long bOff, Pointer[] buf, int index, int length) { boundsCheck(bOff, length * Native.POINTER_SIZE); super.read(bOff, buf, index, length); } ////////////////////////////////////////////////////////////////////////// // Raw write methods ////////////////////////////////////////////////////////////////////////// /** * Indirect the native pointer to malloc space, a la * Pointer.write. But this method performs a bounds * checks to ensure that the indirection does not cause memory outside the * malloced space to be accessed. * * @see Pointer#write(long,byte[],int,int) */ @Override public void write(long bOff, byte[] buf, int index, int length) { boundsCheck(bOff, length * 1L); super.write(bOff, buf, index, length); } /** * Indirect the native pointer to malloc space, a la * Pointer.write. But this method performs a bounds * checks to ensure that the indirection does not cause memory outside the * malloced space to be accessed. * * @see Pointer#write(long,short[],int,int) */ @Override public void write(long bOff, short[] buf, int index, int length) { boundsCheck(bOff, length * 2L); super.write(bOff, buf, index, length); } /** * Indirect the native pointer to malloc space, a la * Pointer.write. But this method performs a bounds * checks to ensure that the indirection does not cause memory outside the * malloced space to be accessed. * * @see Pointer#write(long,char[],int,int) */ @Override public void write(long bOff, char[] buf, int index, int length) { boundsCheck(bOff, length * Native.WCHAR_SIZE); super.write(bOff, buf, index, length); } /** * Indirect the native pointer to malloc space, a la * Pointer.write. But this method performs a bounds * checks to ensure that the indirection does not cause memory outside the * malloced space to be accessed. * * @see Pointer#write(long,int[],int,int) */ @Override public void write(long bOff, int[] buf, int index, int length) { boundsCheck(bOff, length * 4L); super.write(bOff, buf, index, length); } /** * Indirect the native pointer to malloc space, a la * Pointer.write. But this method performs a bounds * checks to ensure that the indirection does not cause memory outside the * malloced space to be accessed. * * @see Pointer#write(long,long[],int,int) */ @Override public void write(long bOff, long[] buf, int index, int length) { boundsCheck(bOff, length * 8L); super.write(bOff, buf, index, length); } /** * Indirect the native pointer to malloc space, a la * Pointer.write. But this method performs a bounds * checks to ensure that the indirection does not cause memory outside the * malloced space to be accessed. * * @see Pointer#write(long,float[],int,int) */ @Override public void write(long bOff, float[] buf, int index, int length) { boundsCheck(bOff, length * 4L); super.write(bOff, buf, index, length); } /** * Indirect the native pointer to malloc space, a la * Pointer.write. But this method performs a bounds * checks to ensure that the indirection does not cause memory outside the * malloced space to be accessed. * * @see Pointer#write(long,double[],int,int) */ @Override public void write(long bOff, double[] buf, int index, int length) { boundsCheck(bOff, length * 8L); super.write(bOff, buf, index, length); } /** * Indirect the native pointer to malloc space, a la * Pointer.write. But this method performs a bounds * checks to ensure that the indirection does not cause memory outside the * malloced space to be accessed. * * @see Pointer#write(long,Pointer[],int,int) */ @Override public void write(long bOff, Pointer[] buf, int index, int length) { boundsCheck(bOff, length * Native.POINTER_SIZE); super.write(bOff, buf, index, length); } ////////////////////////////////////////////////////////////////////////// // Java type read methods ////////////////////////////////////////////////////////////////////////// /** * Indirect the native pointer to malloc space, a la * Pointer.getByte. But this method performs a bounds * checks to ensure that the indirection does not cause memory outside the * malloced space to be accessed. * * @see Pointer#getByte(long) */ @Override public byte getByte(long offset) { boundsCheck(offset, 1); return super.getByte(offset); } /** * Indirect the native pointer to malloc space, a la * Pointer.getByte. But this method performs a bounds * checks to ensure that the indirection does not cause memory outside the * malloced space to be accessed. * * @see Pointer#getByte(long) */ @Override public char getChar(long offset) { boundsCheck(offset, Native.WCHAR_SIZE); return super.getChar(offset); } /** * Indirect the native pointer to malloc space, a la * Pointer.getShort. But this method performs a bounds * checks to ensure that the indirection does not cause memory outside the * malloced space to be accessed. * * @see Pointer#getShort(long) */ @Override public short getShort(long offset) { boundsCheck(offset, 2); return super.getShort(offset); } /** * Indirect the native pointer to malloc space, a la * Pointer.getInt. But this method performs a bounds * checks to ensure that the indirection does not cause memory outside the * malloced space to be accessed. * * @see Pointer#getInt(long) */ @Override public int getInt(long offset) { boundsCheck(offset, 4); return super.getInt(offset); } /** * Indirect the native pointer to malloc space, a la * Pointer.getLong. But this method performs a bounds * checks to ensure that the indirection does not cause memory outside the * malloced space to be accessed. * * @see Pointer#getLong(long) */ @Override public long getLong(long offset) { boundsCheck(offset, 8); return super.getLong(offset); } /** * Indirect the native pointer to malloc space, a la * Pointer.getFloat. But this method performs a bounds * checks to ensure that the indirection does not cause memory outside the * malloced space to be accessed. * * @see Pointer#getFloat(long) */ @Override public float getFloat(long offset) { boundsCheck(offset, 4); return super.getFloat(offset); } /** * Indirect the native pointer to malloc space, a la * Pointer.getDouble. But this method performs a * bounds check to ensure that the indirection does not cause memory * outside the malloced space to be accessed. * * @see Pointer#getDouble(long) */ @Override public double getDouble(long offset) { boundsCheck(offset, 8); return super.getDouble(offset); } /** * Indirect the native pointer to malloc space, a la * Pointer.getPointer. But this method performs * a bounds checks to ensure that the indirection does not cause memory * outside the malloced space to be accessed. * * @see Pointer#getPointer(long) */ @Override public Pointer getPointer(long offset) { boundsCheck(offset, Native.POINTER_SIZE); return shareReferenceIfInBounds(super.getPointer(offset)); } /** * Get a ByteBuffer mapped to a portion of this memory. * We keep a weak reference to all ByteBuffers provided so that this * memory object is not GC'd while there are still implicit outstanding * references to it (it'd be nice if we could attach our own reference to * the ByteBuffer, but the VM generates the object so we have no control * over it). * * @param offset byte offset from pointer to start the buffer * @param length Length of ByteBuffer * @return a direct ByteBuffer that accesses the memory being pointed to, */ @Override public ByteBuffer getByteBuffer(long offset, long length) { boundsCheck(offset, length); ByteBuffer b = super.getByteBuffer(offset, length); // Ensure this Memory object will not be GC'd (and its memory freed) // if the Buffer is still extant. buffers.put(b, this); return b; } @Override public String getString(long offset, String encoding) { // NOTE: we only make sure the start of the string is within bounds boundsCheck(offset, 0); return super.getString(offset, encoding); } @Override public String getWideString(long offset) { // NOTE: we only make sure the start of the string is within bounds boundsCheck(offset, 0); return super.getWideString(offset); } ////////////////////////////////////////////////////////////////////////// // Java type write methods ////////////////////////////////////////////////////////////////////////// /** * Indirect the native pointer to malloc space, a la * Pointer.setByte. But this method performs a bounds * checks to ensure that the indirection does not cause memory outside the * malloced space to be accessed. * * @see Pointer#setByte */ @Override public void setByte(long offset, byte value) { boundsCheck(offset, 1); super.setByte(offset, value); } /** * Indirect the native pointer to malloc space, a la * Pointer.setChar. But this method performs a bounds * checks to ensure that the indirection does not cause memory outside the * malloced space to be accessed. * * @see Pointer#setChar */ @Override public void setChar(long offset, char value) { boundsCheck(offset, Native.WCHAR_SIZE); super.setChar(offset, value); } /** * Indirect the native pointer to malloc space, a la * Pointer.setShort. But this method performs a bounds * checks to ensure that the indirection does not cause memory outside the * malloced space to be accessed. * * @see Pointer#setShort */ @Override public void setShort(long offset, short value) { boundsCheck(offset, 2); super.setShort(offset, value); } /** * Indirect the native pointer to malloc space, a la * Pointer.setInt. But this method performs a bounds * checks to ensure that the indirection does not cause memory outside the * malloced space to be accessed. * * @see Pointer#setInt */ @Override public void setInt(long offset, int value) { boundsCheck(offset, 4); super.setInt(offset, value); } /** * Indirect the native pointer to malloc space, a la * Pointer.setLong. But this method performs a bounds * checks to ensure that the indirection does not cause memory outside the * malloced space to be accessed. * * @see Pointer#setLong */ @Override public void setLong(long offset, long value) { boundsCheck(offset, 8); super.setLong(offset, value); } /** * Indirect the native pointer to malloc space, a la * Pointer.setFloat. But this method performs a bounds * checks to ensure that the indirection does not cause memory outside the * malloced space to be accessed. * * @see Pointer#setFloat */ @Override public void setFloat(long offset, float value) { boundsCheck(offset, 4); super.setFloat(offset, value); } /** * Indirect the native pointer to malloc space, a la * Pointer.setDouble. But this method performs a * bounds checks to ensure that the indirection does not cause memory * outside the malloced space to be accessed. * * @see Pointer#setDouble */ @Override public void setDouble(long offset, double value) { boundsCheck(offset, 8); super.setDouble(offset, value); } /** * Indirect the native pointer to malloc space, a la * Pointer.setPointer. But this method performs * a bounds checks to ensure that the indirection does not cause memory * outside the malloced space to be accessed. * * @see Pointer#setPointer */ @Override public void setPointer(long offset, Pointer value) { boundsCheck(offset, Native.POINTER_SIZE); super.setPointer(offset, value); } @Override public void setString(long offset, String value, String encoding) { boundsCheck(offset, Native.getBytes(value, encoding).length + 1L); super.setString(offset, value, encoding); } @Override public void setWideString(long offset, String value) { boundsCheck(offset, (value.length() + 1L) * Native.WCHAR_SIZE); super.setWideString(offset, value); } @Override public String toString() { return "allocated@0x" + Long.toHexString(peer) + " (" + size + " bytes)"; } protected static void free(long p) { // free(0) is a no-op, so avoid the overhead of the call if (p != 0) { Native.free(p); } } protected static long malloc(long size) { return Native.malloc(size); } /** Dumps the contents of this memory object. */ public String dump() { return dump(0, (int)size()); } /** * Check whether the supplied Pointer object points into the memory region * backed by this memory object. The intention is to prevent premature GC * of the Memory object. * * @param target Pointer to check * @return {@code target} if target does not point into the region covered * by this memory object, a newly {@code SharedMemory} object, if the pointer * points to memory backed by this Memory object. */ private Pointer shareReferenceIfInBounds(Pointer target) { if(target == null) { return null; } long offset = target.peer - this.peer; if (offset >= 0 && offset < this.size) { return this.share(offset); } else { return target; } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy