Flink中MemorySegment用来管理内存,其是一个抽象类,具体实现有HeapMemorySegment和HybirdMemorySegment。
protected static final long BYTE_ARRAY_BASE_OFFSET = UNSAFE.arrayBaseOffset(byte[].class);
BYTE_ARRAY_BASE_OFFSET是byte数组的相对偏移量,当存储为堆内内存的时候,在一直当前MemorySegment存在的情况下,通过Unsafe可以根据当前类的地址通过相对偏移量的到byte数组的地址,这个地址也是具体的内存存放的地方。
protected final byte[] heapMemory;
当选择的是堆内内存的时候,这个heapMemory就是存放存储内容的byte数组。
protected long address;
当内存为堆内内存的时候address为byte数组的相对偏移量,而当为堆外内存的时候,address则为一个内存中的绝对地址。
protected final long addressLimit;
这个参数则是内存边界。
protected final int size;
Size自然是这一MemorySegment的内存大小,堆内内存情况下就是byte数组的长度。
private final Object owner;
Owner则为这一MemorySegment内存当前的使用对象。
具体的操作以int的获取为例子。
public final int getInt(int index) {
final long pos = address + index;
if (index >= 0 && pos <= addressLimit - 4) {
return UNSAFE.getInt(heapMemory, pos);
}
else if (address > addressLimit) {
throw new IllegalStateException("segment has been freed");
}
else {
// index is in fact invalid
throw new IndexOutOfBoundsException();
}
}
在获取制定位置的int的时候,由于int是四个字节,所以所要注意的是代表内存边界的addressLimit需要减4,之后通过unsafe直接获取对应位置上的数据。
public final int getIntLittleEndian(int index) {
if (LITTLE_ENDIAN) {
return getInt(index);
} else {
return Integer.reverseBytes(getInt(index));
}
}
对于小端存储的,需要将得到的数据逆转byte位,得到相应的数据。
MemorySegment之间进行比较的compare()方法比较有意思。
public final int compare(MemorySegment seg2, int offset1, int offset2, int len) {
while (len >= 8) {
long l1 = this.getLongBigEndian(offset1);
long l2 = seg2.getLongBigEndian(offset2);
if (l1 != l2) {
return (l1 < l2) ^ (l1 < 0) ^ (l2 < 0) ? -1 : 1;
}
offset1 += 8;
offset2 += 8;
len -= 8;
}
while (len > 0) {
int b1 = this.get(offset1) & 0xff;
int b2 = seg2.get(offset2) & 0xff;
int cmp = b1 - b2;
if (cmp != 0) {
return cmp;
}
offset1++;
offset2++;
len--;
}
return 0;
}
参数len代表与需要进行比较的目标MemorySegment对象比较范围。
为了加快比较的速度,如果比较的长度大于8,首先会一次性取八个byte也就是八字节转化为long进行比较,加快比较的效率。
如果比较到剩余的位数小于8,那么开始逐字节进行比较,直到比较出相应的结果。