Skip to content

Instantly share code, notes, and snippets.

@ngocdaothanh
Created December 17, 2011 14:00
Show Gist options
  • Save ngocdaothanh/1490276 to your computer and use it in GitHub Desktop.
Save ngocdaothanh/1490276 to your computer and use it in GitHub Desktop.
ByteBuffer.allocateDirect vs Unsafe
object Benchmark {
private val LOOP_COUNT = 1000000
private val ARRAY_SIZE = 1024
def main(args: Array[String]) {
val t1 = System.currentTimeMillis
var i = 0
while (i < LOOP_COUNT) {
testDirectByteBuffer
//testUnsafeMemory
i += 1
}
val t2 = System.currentTimeMillis
println("" + (t2 - t1) + " [ms]")
}
private def testDirectByteBuffer {
val b = java.nio.ByteBuffer.allocateDirect(ARRAY_SIZE)
b.put(new Array[Byte](ARRAY_SIZE))
//DirectByteBufferCleaner.clean(b)
}
private def testUnsafeMemory {
val m = UnsafeMemory.allocate(new Array[Byte](ARRAY_SIZE))
//assert(m.bytes.length == ARRAY_SIZE)
m.free()
}
}
import java.nio.ByteBuffer
/**
* Frees memory of direct buffer allocated by ByteBuffer.allocateDirect
* without waiting for GC.
*
* See:
* http://groups.google.com/group/netty/browse_thread/thread/3be7f573384af977
* https://github.com/netty/netty/issues/62
*/
object DirectByteBufferCleaner {
private val cleanerMethod = {
val klass = Class.forName("java.nio.DirectByteBuffer")
val ret = klass.getDeclaredMethod("cleaner")
ret.setAccessible(true)
ret
}
private val cleanMethod = {
val klass = Class.forName("sun.misc.Cleaner")
klass.getDeclaredMethod("clean")
}
def clean(directByteBuffer: ByteBuffer) {
val cleaner = cleanerMethod.invoke(directByteBuffer)
cleanMethod.invoke(cleaner)
}
}
import sun.misc.Unsafe
import java.lang.{Long => JLong}
// See http://svn.apache.org/viewvc/cassandra/trunk/src/java/org/apache/cassandra/io/util/Memory.java?view=markup
object UnsafeMemory {
val unsafe = {
val field = classOf[Unsafe].getDeclaredField("theUnsafe")
field.setAccessible(true)
field.get(null).asInstanceOf[Unsafe]
}
// Newer?
// http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/nio/Bits.java
val copyFromByteArray = {
try {
val klass = Class.forName("java.nio.Bits")
val method = klass.getDeclaredMethod("copyFromByteArray", classOf[Object], JLong.TYPE, JLong.TYPE, JLong.TYPE)
method.setAccessible(true)
method
} catch {
case _ => null
}
}
// Older?
// http://javasourcecode.org/html/open-source/jdk/jdk-6u23/java/nio/Bits.java.html
val copyFromArray = {
try {
val klass = Class.forName("java.nio.Bits")
val method = klass.getDeclaredMethod("copyFromArray", classOf[Object], JLong.TYPE, JLong.TYPE, JLong.TYPE, JLong.TYPE)
method.setAccessible(true)
method
} catch {
case _ => null
}
}
def copyFromByteArray(bytes: Array[Byte], dst: Long) {
/*
val size = bytes.length
var offset = 0
while (offset < size) {
unsafe.putByte(dst + offset, bytes(offset))
offset += 1
}
*/
if (copyFromByteArray != null)
copyFromByteArray.invoke(null, bytes, new JLong(0), new JLong(dst), new JLong(bytes.length))
else
copyFromArray.invoke(null, bytes, new JLong(16), new JLong(0), new JLong(dst), new JLong(bytes.length))
}
/** Transfers bytes to unsafe memory. */
def allocate(bytes: Array[Byte]): UnsafeMemory = {
val size = bytes.length // Int
val peer = unsafe.allocateMemory(size)
copyFromByteArray(bytes, peer)
new UnsafeMemory(peer, size)
}
}
class UnsafeMemory(private var peer: Long, size: Int) {
import UnsafeMemory.unsafe
// Newer?
// http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/nio/Bits.java
val copyToByteArray = {
try {
val klass = Class.forName("java.nio.Bits")
val method = klass.getDeclaredMethod("copyToByteArray", JLong.TYPE, classOf[Object], JLong.TYPE, JLong.TYPE)
method.setAccessible(true)
method
} catch {
case _ => null
}
}
// Older?
// http://javasourcecode.org/html/open-source/jdk/jdk-6u23/java/nio/Bits.java.html
val copyToArray = {
try {
val klass = Class.forName("java.nio.Bits")
val method = klass.getDeclaredMethod("copyToArray", JLong.TYPE, classOf[Object], JLong.TYPE, JLong.TYPE, JLong.TYPE)
method.setAccessible(true)
method
} catch {
case _ => null
}
}
def copyToByteArray(src: Long, bytes: Array[Byte]) {
/*
val size = bytes.length
var offset = 0
while (offset < size) {
ret(offset) = unsafe.getByte(src + offset)
offset += 1
}
*/
if (copyToByteArray != null)
copyToByteArray.invoke(null, new JLong(src), bytes, new JLong(0), new JLong(bytes.length))
else
copyToArray.invoke(null, new JLong(src), bytes, new JLong(16), new JLong(0), new JLong(bytes.length))
}
/** Transfers unsafe memory to bytes. */
def bytes = {
if (peer == 0) throw new NullPointerException("Unsafe memory has been freed")
val ret = new Array[Byte](size)
copyToByteArray(peer, ret)
ret
}
def free() {
if (peer != 0) {
unsafe.freeMemory(peer)
peer = 0
}
}
override protected def finalize() {
try {
free()
} finally {
super.finalize()
}
}
}
@jnorthrup
Copy link

please paste results?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment