java Unsafe实现堆外缓存

/**
 * val 长度目前需要小于 0xff , 否则会出问题
 * key内存表示{ next_addr(8), hash(4), val_addr(8), size(1/4), len(?) }
 * val内存表示{ size(1/4), len(?) }
 */
public final class Cache2 {
    public int cap, size;
    public long base;
    public final Unsafe unsafe;
    public double factor = 0.75;

    public Cache2() throws NoSuchFieldException, IllegalAccessException {
        this.unsafe = init();
        this.cap = 16;
        this.base = unsafe.allocateMemory(16 * 8);
        fillZero(base, 16 * 8);
    }

    public Cache2(int cap, double factor) throws NoSuchFieldException, IllegalAccessException {
        this.unsafe = init();
        this.cap = cap;
        this.factor = factor;
        this.base = unsafe.allocateMemory(cap * 8L);
        fillZero(base, cap * 8L);
    }

    private Unsafe init() throws NoSuchFieldException, IllegalAccessException {
        Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
        theUnsafe.setAccessible(true);
        return (Unsafe) theUnsafe.get(null);
    }

    public void put(String key, String val) {
        int len = key.length();
        int hash = key.hashCode();
        long index = getIndex(hash);
        long cur = unsafe.getAddress(index);
        long next = 0;
        if (0 != cur) {
            do {
                next = cur;
                if (hash == unsafe.getInt(cur + 8)) {
                    int size = getSize(cur + 8 + 4 + 8, len);
                    if (size == len) {
                        long valAddrOffset = cur + 8 + 4;
                        long this_bytes_addr = valAddrOffset + 8 + (size < 128 ? 1 : 4);
                        if (checkByte(this_bytes_addr, size, key.getBytes(StandardCharsets.UTF_8))) {
                            unsafe.freeMemory(unsafe.getAddress(valAddrOffset));
                            unsafe.putAddress(valAddrOffset, putString(val, 0));
                        }
                    }
                }
                cur = unsafe.getAddress(cur);
            } while (cur != 0);
        }
        if (++size * factor > cap) {
            System.out.println("扩容");
        }
        long keyAddr = putString(key, 8 + 4 + 8);
        long valAddr = putString(val, 0);
        fillZero(keyAddr, 8L);
        unsafe.putInt(keyAddr + 8, hash);
        unsafe.putAddress(keyAddr + 8 + 4, valAddr);
        unsafe.putAddress(next == 0 ? index : next, keyAddr);
    }

    public String get(String key) {
        int hash = key.hashCode();
        long cur = unsafe.getAddress(getIndex(hash));
        if (0 == cur) return null;
        int len = key.length();
        do {
            long hashOffset = cur + 8, valAddrOffset = hashOffset + 4, sizeOffset = valAddrOffset + 8;
            if (hash == unsafe.getInt(hashOffset)) {
                int size = getSize(sizeOffset, len);
                if (size == len) {
                    long this_bytes_addr = sizeOffset + (size < 128 ? 1 : 4);
                    if (checkByte(this_bytes_addr, size, key.getBytes(StandardCharsets.UTF_8))) {
                        return getString(unsafe.getAddress(valAddrOffset));
                    }
                }
            }
            cur = unsafe.getAddress(cur);
        } while (cur != 0);
        return null;
    }

    private synchronized long putString(String str, int offset) {
        byte[] bytes = str.getBytes(StandardCharsets.UTF_8);
        int len = bytes.length, strSize = len < 128 ? 1 : 4;
        long start = unsafe.allocateMemory(offset + strSize + len) + offset;
        if (len < 128) {
            unsafe.putByte(start, (byte) len);
        } else {
            unsafe.putInt(start, len);
        }
        putByte(bytes, start + strSize, len);
        return start - offset;
    }

    private synchronized String getString(long addr) {
        int size;
        if ((size = unsafe.getByte(addr)) < 0) {
            size = unsafe.getInt(addr);
            addr += 4;
        } else ++addr;
        //TODO 优化byte数组操作为堆外内存赋值
        byte[] bytes = new byte[size];
        for (int i = 0; i < size; ++i) bytes[i] = unsafe.getByte(addr + i);
        return new String(bytes, StandardCharsets.UTF_8);
    }

    private synchronized void putByte(byte[] bytes, long offsetStart, int len) {
        for (int i = 0; i < len; ++i) unsafe.putByte(offsetStart + i, bytes[i]);
    }

    public synchronized long getIndex(int hash) {
        int offset = ((cap - 1) & hash) << 3;
        return base + offset;
    }

    private synchronized int getSize(long address, int len) {
        return len < 128 ? unsafe.getByte(address) : unsafe.getInt(address);
    }

    private synchronized void fillZero(long addr, long cap) {
        this.unsafe.setMemory(addr, cap, (byte) 0);
    }

    private synchronized boolean checkByte(long addr, int size, byte[] bytes) {
        for (int i = 0; i < size; ++i) {
            if (unsafe.getByte(addr + i) != bytes[i]) {
                return false;
            }
        }
        return true;
    }

    public synchronized void clear() {
        for (int i = 0; i < cap; ++i) {
            long address = unsafe.getAddress(base + i * 8L);
            if (address == 0) continue;
            do {
                long valAddr = unsafe.getAddress(address + 8 + 4);
                unsafe.freeMemory(valAddr);
                address = unsafe.getAddress(address);
            } while (address != 0);
        }
        unsafe.freeMemory(base);
    }

    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
        Cache2 cache2 = new Cache2();
        cache2.put("name", "Administrator");
        cache2.put("wcg", "admin");
        System.out.println(cache2.get("name"));
        System.out.println(cache2.get("wcg"));
        cache2.clear();
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值