Tutorials     About     RSS
Tech and Media Labs


Jakob Jenkov
Last update: 2019-05-27

The Mem Ops BytesAllocatorManualDefrag class is capable of allocating smaller sections (blocks) of a bigger byte array. Thus, a single, big byte array can be instantiated, and allocated into smaller sections which can be used as if they were separate byte arrays. You just need to know the start offset of the byte array section you have been allocated, and it's length, and you are good to go.

When you are done using an allocated byte array section you must explicitly free it. When you free a byte array section, the ByteArrayAllocatorAutoDefrag class will mark it as free, but will not defragment the underlying byte array until you explicitly to tell it to. This is how BytesAllocatorManualDefrag is different from the ByteArrayAllocatorAutoDefrag.

The principle of not defragmenting free blocks immediate we refer to as deferred defragmentation.

Create a BytesAllocatorManualDefrag

To use the BytesAllocatorManualDefrag class you must first create an instance of it. Here is an example of creating a BytesAllocatorManualDefrag instance:

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

Notice that you have to pass the underlying byte array as parameter to the BytesAllocatorManualDefrag. It is this byte array which you can allocate smaller sections (blocks) from. This way you will only ever have this underlying byte array allocated in the JVM. Your memory consumption remains completely stable, and no garbage collection needs to take place.

Allocate a Block

In order to allocate a block (section) of bytes from the underlying byte array, you call the allocate() method. Once allocated, no other allocate() call can allocate the same block until it has been freed. The allocate() method returns the offset into the big, underlying byte array where the allocated block starts. If no block could be allocated, -1 is returned. Here is an example of allocating a block of 1024 bytes:

int offset = allocator.allocate(1024);

Getting a Reference to the Byte Array

You can get a reference to the underlying byte array via the getData() method. Your allocated block will reside at the returned offset inside this byte array. Here is how obtaining the byte array looks:

byte[] data = allocator.getData();

Accessing the Allocated Block

Once you have allocated a block of bytes from the BytesAllocatorManualDefrag you can access it via the data array, from the offset returned by allocate() and until offset + length - 1. Here is an example of accessing an allocated block of bytes from a 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

Notice the two last lines of the example. These two lines access the first and last byte of the allocated block. You can access all bytes from the first byte to the last byte this way.

Free a Block

Once you are finished with a memory block you must free it again. You free it using the free() method. The free() method takes the start and end offset of the block to free. Here is an example of allocating and freeing a byte block:

int offset = allocator.allocate(1024);

allocator.free(offset, offset + 1024);

Defragment Free Blocks

After freeing a number of previously allocated blocks from the underlying byte array, you will need to defragment the free blocks. Defragmenting the free blocks means joining adjacent free blocks into a single free block.

Remember, from a free block you can only allocate a byte block of the free block's size or smaller. If you allocate a smaller block from a free block, the free block is then broken up into two smaller blocks (one of which is the one just allocated). When the allocated block is freed, it is then marked internally as its own free block.

If you do not defragment the free blocks, sooner or later you will end up with a lot of small free blocks. This means, that you will be able to allocate only smaller and smaller blocks.

To defragment the free blocks you call the defragment() method of the BytesAllocatorManualDefrag . Here is how calling defragment() looks:


When to Defragment Free Blocks

Using deferred defragmentation makes sense in cases where you have to respond to an incoming request as fast as possible, and where your system will have idle time later during which it can defragment the free blocks. It is during such idle times you should call defragment() .

If your system is constantly very busy, there may never be an idle period during which to call defragment(). Calling defragment() will most likely result in a longer pause than if you immediately defragment free blocks like the ByteArrayAllocatorAutoDefrag does. Thus, if your system is constantly very busy, you might be better off using the ByteArrayAllocatorAutoDefrag than the BytesAllocatorManualDefrag. As you can see, it depends on your system's load pattern.

Full BytesAllocatorManualDefrag Example

Here is a full example showing how to allocate and free a memory block from a Mem Ops BytesAllocatorManualDefrag :

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

Jakob Jenkov

Featured Videos

Thread Congestion in Java - Video Tutorial

Sponsored Ads

Maildroppa - Smart Email Marketing Solution
Close TOC

All Trails

Trail TOC

Page TOC