BytesAllocatorManualDefrag

时间:2020-01-09 10:36:57  来源:igfitidea点击:

Mem Ops BytesAllocatorManualDefrag类(字节分配器手动碎片整理)能够分配较大字节数组的较小部分(块)。因此,可以实例化一个大字节数组,并将其分配给较小的部分,就可以将它们当作单独的字节数组使用。我们只需要知道已分配的字节数组部分的起始偏移量及其长度,就可以了。

使用分配的字节数组部分完成操作后,必须显式释放它。当我们释放字节数组节时,ByteArrayAllocatorAutoDefrag类会将其标记为空闲,但不会对基础字节数组进行碎片整理,直到我们明确告知它为止。这就是BytesAllocatorManualDefrag与ByteArrayAllocatorAutoDefrag的不同之处。

不对自由块立即进行碎片整理的原理称为延迟碎片整理。

创建一个BytesAllocatorManualDefrag

要使用BytesAllocatorManualDefrag类,我们必须首先创建一个实例。这是创建BytesAllocatorManualDefrag实例的示例:

BytesAllocatorManualDefrag allocator =
    new BytesAllocatorManualDefrag(new byte[1024 * 1024]);

注意,我们必须将底层字节数组作为参数传递给BytesAllocatorManualDefrag。我们可以从该字节数组中分配较小的部分(块)。这样,我们将仅在JVM中分配此基础字节数组。内存消耗保持完全稳定,并且不需要进行垃圾收集。

分配块

为了从底层字节数组中分配字节的一个块(部分),请调用allocate()方法。一旦分配完,其他的" allocate()"调用就无法分配相同的块,直到它被释放为止。 allocate()方法将偏移量返回到大的底层字节数组中,在该数组中已分配的块开始。如果无法分配任何块,则返回-1. 这是分配1024个字节的块的示例:

int offset = allocator.allocate(1024);

获取对字节数组的引用

我们可以通过getData()方法获取对底层字节数组的引用。我们分配的块将驻留在此字节数组内返回的偏移量处。这是获取字节数组的样子:

byte[] data = allocator.getData();

访问分配的块

一旦从" BytesAllocatorManualDefrag"中分配了一个字节块,就可以通过数据数组访问它,从" allocate()"返回的偏移量开始,直到" offset + length 1"。这是一个从BytesAllocatorManualDefrag访问分配的字节块的例子:

int blockLength = 1024;
int offset = allocator.allocate(blockLength);
byte[] data = allocator.getData();

data[offset] = 1;                   //first byte of block
data[offset + blockLength -1] = 2;  //last byte of block

注意示例的最后两行。这两行访问分配的块的第一个和最后一个字节。我们可以通过这种方式访问从第一个字节到最后一个字节的所有字节。

释放一块

完成存储块后,必须再次释放它。我们可以使用free()方法释放它。 free()方法将块的开始和结束偏移量释放。这是分配和释放字节块的示例:

int offset = allocator.allocate(1024);

allocator.free(offset, offset + 1024);

无碎片整理块

从基础字节数组中释放许多先前分配的块后,需要对可用块进行碎片整理。对空闲块进行碎片整理意味着将相邻的空闲块合并为一个空闲块。

请记住,在空闲块中,我们只能分配空闲块大小或者更小的字节块。如果从空闲块中分配一个较小的块,则该空闲块将分成两个较小的块(其中一个是刚刚分配的块)。释放分配的块后,内部将其标记为自己的空闲块。

如果不对可用块进行碎片整理,则迟早会得到很多小的可用块。这意味着我们将只能分配越来越小的块。

要对可用块进行碎片整理,请调用" BytesAllocatorManualDefrag"的" defragment()"方法。这是调用defragment()的样子:

allocator.defragment();

何时对自由块进行碎片整理

在以下情况下,使用延迟碎片整理很有意义:在这种情况下,我们必须尽可能快地响应传入的请求,并且系统稍后会有空闲时间可以对可用块进行碎片整理。在这种空闲时间,我们应该调用defragment()

如果系统一直很忙,则可能永远不会有空闲时间来调用" defragment()"。与立即对可用块进行碎片整理(如ByteArrayAllocatorAutoDefrag那样)相比,调用defragment()最有可能导致更长的暂停时间。因此,如果系统一直很忙,那么使用ByteArrayAllocatorAutoDefrag可能比使用BytesAllocatorManualDefrag更好。如我们所见,这取决于系统的负载模式。

Full BytesAllocatorManualDefrag示例

这是一个完整的示例,显示了如何从Mem OpsBytesAllocatorManualDefrag中分配和释放内存块:

int offset = allocator.allocate(1024);

byte[] data = allocator.getData();

data[offset] = 1;                   //first byte of block
data[offset + blockLength -1] = 2;  //last byte of block

//do something more with written bytes.

allocator.free(offset, offset + 1024);

allocator.defragment();   // defragment if necessary / fits