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 java.lang.reflect.Method; 020import java.nio.ByteBuffer; 021import java.util.concurrent.atomic.AtomicBoolean; 022 023import static java.nio.ByteOrder.LITTLE_ENDIAN; 024 025/** 026 * Implementation of {@link OffHeapMemory} using {@link ByteBuffer#allocateDirect(int)} 027 * 028 * @author alexkasko 029 * Date: 1/14/13 030*/ 031class DirectOffHeapMemory extends OffHeapMemory { 032 033 private final ByteBuffer bb; 034 private final long length; 035 private Object cleaner; 036 private Method clean; 037 private final AtomicBoolean disposed = new AtomicBoolean(false); 038 039 DirectOffHeapMemory(long bytes) { 040 if(bytes > Integer.MAX_VALUE) throw new IllegalArgumentException( 041 "Long-sized allocations are not supported by [" + getClass().getName() + "]"); 042 this.length = bytes; 043 this.bb = ByteBuffer.allocateDirect((int) bytes).order(LITTLE_ENDIAN); 044 // http://stackoverflow.com/a/8191493/314015 045 try { 046 setupOpenJdkCleaner(); 047 } catch (Exception e) { 048 try { 049 setupAndroidCleaner(); 050 } catch (Exception e1) { 051 e.printStackTrace(); 052 e1.printStackTrace(); 053 throw new RuntimeException(e); 054 } 055 } 056 } 057 058 private void setupOpenJdkCleaner() throws Exception { 059 Method cleanerMethod = bb.getClass().getMethod("cleaner"); 060 cleanerMethod.setAccessible(true); 061 this.cleaner = cleanerMethod.invoke(bb); 062 this.clean = cleaner.getClass().getMethod("clean"); 063 this.clean.setAccessible(true); 064 } 065 066 private void setupAndroidCleaner() throws Exception { 067 this.clean = bb.getClass().getMethod("free"); 068 this.clean.setAccessible(true); 069 this.cleaner = bb; 070 } 071 072 /** 073 * {@inheritDoc} 074 */ 075 @Override 076 public boolean isUnsafe() { 077 return false; 078 } 079 080 /** 081 * {@inheritDoc} 082 */ 083 @Override 084 public long length() { 085 return length; 086 } 087 088 /** 089 * {@inheritDoc} 090 */ 091 @Override 092 public void free() { 093 if(!disposed.compareAndSet(false, true)) return; 094 try { 095 clean.invoke(cleaner); 096 } catch (Throwable e) { 097 e.printStackTrace(); 098 } 099 } 100 101 /** 102 * {@inheritDoc} 103 */ 104 @Override 105 public void put(long offset, byte[] buffer, int bufferOffset, int bytes) { 106 bb.clear().position((int) offset); 107 bb.put(buffer, bufferOffset, bytes); 108 } 109 110 /** 111 * {@inheritDoc} 112 */ 113 @Override 114 public void put(long offset, byte[] buffer) { 115 bb.clear().position((int) offset); 116 bb.put(buffer); 117 } 118 119 /** 120 * {@inheritDoc} 121 */ 122 @Override 123 public void get(long offset, byte[] buffer, int bufferOffset, int bytes) { 124 bb.clear().position((int) offset); 125 bb.get(buffer, bufferOffset, bytes); 126 } 127 128 /** 129 * {@inheritDoc} 130 */ 131 @Override 132 public void get(long offset, byte[] buffer) { 133 bb.clear().position((int) offset); 134 bb.get(buffer); 135 } 136 137 /** 138 * {@inheritDoc} 139 */ 140 @Override 141 public byte getByte(long offset) { 142 return bb.get((int) offset); 143 } 144 145 /** 146 * {@inheritDoc} 147 */ 148 @Override 149 public void putByte(long offset, byte value) { 150 bb.put((int) offset, value); 151 } 152 153 /** 154 * {@inheritDoc} 155 */ 156 @Override 157 public short getUnsignedByte(long offset) { 158 return (short) (bb.get((int) offset) & 0xff); 159 } 160 161 /** 162 * {@inheritDoc} 163 */ 164 @Override 165 public void putUnsignedByte(long offset, short value) { 166 bb.put((int) offset, (byte) value); 167 } 168 169 /** 170 * {@inheritDoc} 171 */ 172 @Override 173 public short getShort(long offset) { 174 return bb.getShort((int) offset); 175 } 176 177 /** 178 * {@inheritDoc} 179 */ 180 @Override 181 public void putShort(long offset, short value) { 182 bb.putShort((int) offset, value); 183 } 184 185 /** 186 * {@inheritDoc} 187 */ 188 @Override 189 public int getUnsignedShort(long offset) { 190 return bb.getShort((int) offset) & 0xffff; 191 } 192 193 /** 194 * {@inheritDoc} 195 */ 196 @Override 197 public void putUnsignedShort(long offset, int value) { 198 bb.putShort((int) offset, (short) value); 199 } 200 201 /** 202 * {@inheritDoc} 203 */ 204 @Override 205 public int getInt(long offset) { 206 return bb.getInt((int) offset); 207 } 208 209 /** 210 * {@inheritDoc} 211 */ 212 @Override 213 public void putInt(long offset, int value) { 214 bb.putInt((int) offset, value); 215 } 216 217 /** 218 * {@inheritDoc} 219 */ 220 @Override 221 public long getUnsignedInt(long offset) { 222 return bb.getInt((int) offset) & 0xffffffffL; 223 } 224 225 /** 226 * {@inheritDoc} 227 */ 228 @Override 229 public void putUnsignedInt(long offset, long value) { 230 bb.putInt((int) offset, (int) value); 231 } 232 233 /** 234 * {@inheritDoc} 235 */ 236 @Override 237 public long getLong(long offset) { 238 return bb.getLong((int) offset); 239 } 240 241 /** 242 * {@inheritDoc} 243 */ 244 @Override 245 public void putLong(long offset, long value) { 246 bb.putLong((int) offset, value); 247 } 248 249 /** 250 * {@inheritDoc} 251 */ 252 @Override 253 public void copy(long offset, OffHeapMemory destination, long destOffset, long bytes) { 254 DirectOffHeapMemory dest = (DirectOffHeapMemory) destination; 255 bb.clear().position((int) offset); 256 dest.bb.clear().position((int) destOffset); 257 dest.bb.put(bb); 258 } 259 260 /** 261 * {@inheritDoc} 262 */ 263 @Override 264 public OffHeapMemory clone() { 265 DirectOffHeapMemory res = new DirectOffHeapMemory(length); 266 copy(0, res, 0, length); 267 return res; 268 } 269 270 /** 271 * {@inheritDoc} 272 */ 273 @Override 274 public String toString() { 275 final StringBuilder sb = new StringBuilder(); 276 sb.append("DirectOffHeapMemory"); 277 sb.append("{bb=").append(bb); 278 sb.append(", length=").append(length); 279 sb.append(", cleaner=").append(cleaner); 280 sb.append(", clean=").append(clean); 281 sb.append(", disposed=").append(disposed); 282 sb.append('}'); 283 return sb.toString(); 284 } 285}