Created
January 6, 2015 21:07
-
-
Save arturmkrtchyan/99a0a552853db77db60b to your computer and use it in GitHub Desktop.
Java Off/On Heap Struct/Object Creation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import sun.misc.Cleaner; | |
import sun.misc.Unsafe; | |
import sun.nio.ch.DirectBuffer; | |
import java.lang.reflect.Field; | |
import java.nio.ByteBuffer; | |
// How to run: | |
// struct: javac ObjectVsStruct.java && java ObjectVsStruct struct | |
// object: javac ObjectVsStruct.java && java ObjectVsStruct object | |
public class ObjectVsStruct { | |
private static final int NUM_RECORDS = 20 * 1000 * 1000; | |
private static Buffer buffer; | |
private static Item[] array; | |
public static void main(String[] args) { | |
final long startTime = System.currentTimeMillis(); | |
int numberOfRecords; | |
if(args != null && args.length != 0 && "struct".equals(args[0])) { | |
numberOfRecords = createOffHeapObjects(); | |
} else { | |
numberOfRecords = createOnHeapObjects(); | |
} | |
final long endTime = System.currentTimeMillis(); | |
System.out.printf("Number of records %,d - Elapsed time: %d ms\n", | |
numberOfRecords, (endTime - startTime)); | |
} | |
private static int createOffHeapObjects() { | |
buffer = new UnsafeBuffer(); | |
buffer.allocate(NUM_RECORDS * ItemStruct.getObjectSize()); | |
for (int i = 0; i < NUM_RECORDS; i++) { | |
final ItemStruct item = getItemStruct(i); | |
item.setId(i); | |
item.setKey(123); | |
item.setValue(777); | |
} | |
int numberOfRecords = 0; | |
for (int i = 0; i < NUM_RECORDS; i++) { | |
final ItemStruct item = getItemStruct(i); | |
numberOfRecords = item.getId(); | |
} | |
buffer.free(); | |
return numberOfRecords; | |
} | |
private static int createOnHeapObjects() { | |
array = new Item[NUM_RECORDS]; | |
for (int i = 0; i < NUM_RECORDS; i++) { | |
final Item item = getItemObject(i); | |
item.setId(i); | |
item.setKey(123); | |
item.setValue(777); | |
} | |
int numberOfRecords = 0; | |
for (int i = 0; i < NUM_RECORDS; i++) { | |
final Item item = getItemObject(i); | |
numberOfRecords = item.getId(); | |
} | |
return numberOfRecords; | |
} | |
private static ItemStruct getItemStruct(final int index) { | |
itemStruct.setObjectOffset(buffer.getOffset() + (index * ItemStruct.getObjectSize())); | |
return itemStruct; | |
} | |
private static Item getItemObject(final int index) { | |
if(array[index] == null) { | |
array[index] = new Item(); | |
} | |
return array[index]; | |
} | |
private static final ItemStruct itemStruct = new ItemStruct(); | |
private static class ItemStruct { | |
private static long offset = 0; | |
private static final long idOffset = (offset += 0); | |
private static final long keyOffset = (offset += 4); | |
private static final long valueOffset = (offset += 4); | |
private static final long objectSize = offset += 4; | |
private long objectOffset; | |
public void setObjectOffset(final long objectOffset) { | |
this.objectOffset = objectOffset; | |
} | |
public static long getObjectSize() { | |
return objectSize; | |
} | |
public int getId() { | |
return buffer.getInt(objectOffset + idOffset); | |
} | |
public void setId(final int id) { | |
buffer.putInt(objectOffset + idOffset, id); | |
} | |
public int getKey() { | |
return buffer.getInt(objectOffset + keyOffset); | |
} | |
public void setKey(final int key) { | |
buffer.putInt(objectOffset + keyOffset, key); | |
} | |
public int getValue() { | |
return buffer.getInt(objectOffset + keyOffset); | |
} | |
public void setValue(final int valueSize) { | |
buffer.putInt(objectOffset + valueOffset, valueSize); | |
} | |
} | |
private static class Item { | |
private int id; | |
private int key; | |
private int value; | |
public int getId() { | |
return id; | |
} | |
public void setId(int id) { | |
this.id = id; | |
} | |
public int getKey() { | |
return key; | |
} | |
public void setKey(int key) { | |
this.key = key; | |
} | |
public int getValue() { | |
return value; | |
} | |
public void setValue(int value) { | |
this.value = value; | |
} | |
} | |
private interface Buffer { | |
public void allocate(final long size); | |
public void free(); | |
public void putInt(final long address, final int value); | |
public int getInt(final long address); | |
public long getOffset(); | |
} | |
private static class UnsafeBuffer implements Buffer { | |
private static final Unsafe unsafe; | |
static { | |
try { | |
Field field = Unsafe.class.getDeclaredField("theUnsafe"); | |
field.setAccessible(true); | |
unsafe = (Unsafe)field.get(null); | |
} | |
catch (Exception e) { | |
throw new RuntimeException(e); | |
} | |
} | |
private long address; | |
@Override | |
public void allocate(final long size) { | |
address = unsafe.allocateMemory(size); | |
} | |
@Override | |
public void free() { | |
unsafe.freeMemory(address); | |
} | |
@Override | |
public long getOffset() { | |
return address; | |
} | |
@Override | |
public void putInt(long address, int value) { | |
unsafe.putInt(address, value); | |
} | |
@Override | |
public int getInt(long address) { | |
return unsafe.getInt(address); | |
} | |
} | |
private static class HeapByteBuffer implements Buffer { | |
private ByteBuffer buffer; | |
@Override | |
public void allocate(final long size) { | |
buffer = ByteBuffer.allocate((int)size); | |
} | |
@Override | |
public void free() { | |
} | |
@Override | |
public void putInt(long address, int value) { | |
buffer.putInt((int)address, value); | |
} | |
@Override | |
public int getInt(long address) { | |
return buffer.getInt((int) address); | |
} | |
@Override | |
public long getOffset() { | |
return 0; | |
} | |
} | |
private static class DirectByteBuffer implements Buffer { | |
private ByteBuffer buffer; | |
@Override | |
public void allocate(final long size) { | |
buffer = ByteBuffer.allocateDirect((int) size); | |
} | |
@Override | |
public void free() { | |
Cleaner cleaner = ((DirectBuffer)buffer).cleaner(); | |
if (cleaner != null) cleaner.clean(); | |
} | |
@Override | |
public void putInt(long address, int value) { | |
buffer.putInt((int)address, value); | |
} | |
@Override | |
public int getInt(long address) { | |
return buffer.getInt((int) address); | |
} | |
@Override | |
public long getOffset() { | |
return 0; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment