001/* 002 * Copyright 2013 Alex Kasko (alexkasko.com) 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package com.alexkasko.unsafe.offheap; 018 019import com.alexkasko.unsafe.bytearray.ByteArrayTool; 020 021import java.lang.reflect.InvocationTargetException; 022 023/** 024 * <p>Allocates an area of off-heap memory that is not a subject to GC. 025 * Default implementation uses {@code sun.misc.Unsafe}, with all operations guarded with {@code assert} 026 * boundary checks. 027 * With assert enabled in runtime ({@code -ea} java switch) {@link AssertionError} 028 * will be thrown on illegal input. Without assertions illegal input will crash JVM. 029 * 030 * <p>Fallback implementation uses {@link java.nio.ByteBuffer#allocateDirect(int)} that may (OpenJDK) 031 * or may not (Dalvik) use {@code sun.misc.Unsafe} under the hood. 032 * Note: only unsafe implementation ({@link #allocateMemoryUnsafe(long)}) may use memory areas longer than {@code Integer.MAX_VALUE} 033 * 034 * <p>Unsafe implementation uses native endianness (LE on most platforms). Fallback implementation uses Little Endian byte order. 035 * 036 * <p>Provides methods to access allocated memory. More complex data structures (off-heap quasi-objects) may be 037 * constructed wrapping this class, see {@link com.alexkasko.unsafe.offheaplong.OffHeapLongArray}. 038 * 039 * <p>Memory may be freed manually calling {@link #free()} (thread-safe and may be called safely more than one time), 040 * or it will be freed when {@link OffHeapMemory} instance itself will be garbage collected. 041 * 042 * @author alexkasko 043 * Date: 1/14/13 044 */ 045public abstract class OffHeapMemory { 046 /** 047 * Allocates memory using {@code sun.misc.Unsafe} if it's proper implementation is available. 048 * Allocates using {@link java.nio.ByteBuffer#allocateDirect(int)} otherwise. 049 * 050 * @param bytes amount of memory to allocate 051 * @return {@code OffHeapMemory} instance 052 */ 053 public static OffHeapMemory allocateMemory(long bytes) { 054 try { 055 return allocateMemoryUnsafe(bytes); 056 } catch (Exception e) { 057 // check OOM Error and rethrow it 058 if(e instanceof InvocationTargetException && 059 null != e.getCause() && 060 e.getCause() instanceof OutOfMemoryError) { 061 throw new RuntimeException(e); 062 } 063 return allocateMemoryDirect(bytes); 064 } 065 } 066 067 /** 068 * Allocates memory using {@code sun.misc.Unsafe} 069 * 070 * @param bytes amount of memory to allocate 071 * @return {@code OffHeapMemory} instance 072 * @throws Exception if proper {@code sun.misc.Unsafe} not available 073 */ 074 public static OffHeapMemory allocateMemoryUnsafe(long bytes) throws Exception { 075 try { 076 Class<? extends OffHeapMemory> unsafeMaClass = OffHeapMemory.class 077 .getClassLoader() 078 .loadClass(OffHeapMemory.class.getPackage().getName() + ".UnsafeOffHeapMemory") 079 .asSubclass(OffHeapMemory.class); 080 return unsafeMaClass.getDeclaredConstructor(long.class).newInstance(bytes); 081 } catch (Throwable t) { 082 throw t instanceof Exception ? (Exception) t : new RuntimeException(t); 083 } 084 } 085 086 /** 087 * Allocates memory using {@link java.nio.ByteBuffer#allocateDirect(int)} 088 * 089 * @param bytes amount of memory to allocate 090 * @return {@code OffHeapMemory} instance 091 */ 092 public static OffHeapMemory allocateMemoryDirect(long bytes) { 093 return new DirectOffHeapMemory(bytes); 094 } 095 096 /** 097 * Allocates memory using byte array 098 * 099 * @param bytes amount of memory to allocate 100 * @param bt byte array tool to use for on-heap memory management 101 * @return {@code OffHeapMemory} instance 102 */ 103 public static OffHeapMemory allocateMemoryOnHeap(ByteArrayTool bt, long bytes) { 104 return new OnHeapMemory(bt, bytes); 105 } 106 107 /** 108 * Whether current implementation uses {@code sun.misc.Unsafe} 109 * 110 * @return whether unsafe 111 */ 112 public abstract boolean isUnsafe(); 113 114 /** 115 * Returns length of allocated memory area 116 * 117 * @return length of allocated memory area 118 */ 119 public abstract long length(); 120 121 /** 122 * Frees allocated memory, may be called multiple times from any thread 123 */ 124 public abstract void free(); 125 126 /** 127 * Copies byte array contents into memory area 128 * 129 * @param offset memory area offset 130 * @param buffer source byte array 131 * @param bufferOffset position in byte array 132 * @param bytes bytes length to copy 133 */ 134 public abstract void put(long offset, byte[] buffer, int bufferOffset, int bytes); 135 136 /** 137 * Copies byte array contents into memory area 138 * 139 * @param offset memory area offset 140 * @param buffer source byte array 141 */ 142 public abstract void put(long offset, byte[] buffer); 143 144 /** 145 * Copies part of memory area into byte array 146 * 147 * @param offset memory area offset 148 * @param buffer destination byte array 149 * @param bufferOffset position in byte array 150 * @param bytes bytes length to copy 151 */ 152 public abstract void get(long offset, byte[] buffer, int bufferOffset, int bytes); 153 154 /** 155 * Copies part of memory area into byte array 156 * 157 * @param offset memory area offset 158 * @param buffer destination byte array 159 */ 160 public abstract void get(long offset, byte[] buffer); 161 162 /** 163 * Gets byte from memory area 164 * 165 * @param offset memory area offset 166 * @return byte value 167 */ 168 public abstract byte getByte(long offset); 169 170 /** 171 * Puts byte into memory area 172 * 173 * @param offset memory area offset 174 * @param value byte value 175 */ 176 public abstract void putByte(long offset, byte value); 177 178 /** 179 * Gets one byte (stored as one signed byte), converts it to unsigned 180 * and returns it as short 181 * 182 * @param offset memory area offset 183 * @return unsigned byte as short 184 */ 185 public abstract short getUnsignedByte(long offset); 186 187 /** 188 * Puts short with value from 0 to 255 inclusive into memory area as one 189 * signed byte 190 * 191 * @param offset memory area offset 192 * @param value unsigned byte as short 193 */ 194 public abstract void putUnsignedByte(long offset, short value); 195 196 /** 197 * Gets two bytes from memory area as short 198 * 199 * @param offset memory area offset 200 * @return short value 201 */ 202 public abstract short getShort(long offset); 203 204 /** 205 * Puts short into memory area as two bytes 206 * 207 * @param offset memory area offset 208 * @param value short value 209 */ 210 public abstract void putShort(long offset, short value); 211 212 /** 213 * Gets unsigned short from memory area (stored as two bytes) and returns it as int 214 * 215 * @param offset memory area offset 216 * @return unsigned short as int 217 */ 218 public abstract int getUnsignedShort(long offset); 219 220 /** 221 * Puts int with value from 0 to 65535 inclusive into memory are as two bytes 222 * 223 * @param offset memory area offset 224 * @param value unsigned short as int 225 */ 226 public abstract void putUnsignedShort(long offset, int value); 227 228 /** 229 * Gets four bytes from memory area as int 230 * 231 * @param offset memory area offset 232 * @return int value 233 */ 234 public abstract int getInt(long offset); 235 236 /** 237 * Puts int into memory area as four bytes 238 * 239 * @param offset memory area offset 240 * @param value int value 241 */ 242 public abstract void putInt(long offset, int value); 243 244 /** 245 * Gets unsigned int (stored as 4 bytes) and returns it as long 246 * 247 * @param offset memory area offset 248 * @return unsigned int as long 249 */ 250 public abstract long getUnsignedInt(long offset); 251 252 /** 253 * Puts long value from 0 to 4294967295 inclusive into memory area as four bytes 254 * 255 * @param offset memory area offset 256 * @param value unsigned int as long 257 */ 258 public abstract void putUnsignedInt(long offset, long value); 259 260 /** 261 * Gets eight bytes from memory area as long 262 * 263 * @param offset memory area offset 264 * @return long value 265 */ 266 public abstract long getLong(long offset); 267 268 /** 269 * Puts long into memory area as eight bytes 270 * 271 * @param offset memory area offset 272 * @param value long value 273 */ 274 public abstract void putLong(long offset, long value); 275 276 /** 277 * Copies memory from this instance's area into another instance's area 278 * 279 * @param offset this memory area offset 280 * @param destination destination memory area 281 * @param destOffset destination memory area offset 282 * @param bytes memory length in bytes to copy 283 */ 284 public abstract void copy(long offset, OffHeapMemory destination, long destOffset, long bytes); 285 286 /** 287 * Creates new instance of {@link OffHeapMemory} 288 * and copies there current instance contents 289 * 290 * @return new instance of {@link OffHeapMemory} 291 */ 292 @Override 293 public abstract OffHeapMemory clone(); 294}