Skip to content

JdkZlibEncoder can use pooled heap buffers for deflater input#11891

Merged
normanmaurer merged 4 commits intonetty:4.1from
dferstay:zlib-encoder-uses-pooled-heap-buffers
Dec 8, 2021
Merged

JdkZlibEncoder can use pooled heap buffers for deflater input#11891
normanmaurer merged 4 commits intonetty:4.1from
dferstay:zlib-encoder-uses-pooled-heap-buffers

Conversation

@dferstay
Copy link
Contributor

@dferstay dferstay commented Dec 4, 2021

Motivation:

Previously, when the input ByteBuf was not heap allocated we copied the
input into a new byte array allocated on the heap for every encode() call.
This puts high-throughput clients that use the JdkZlibEncoder under memory
pressure.

Modifications:

Now, when the input ByteBuf is not heap allocated we copy the input into a
heap ByteBuf allocated from the configured ByteBufAllocator (which might be pooled), releasing it after
the encode() has completed.

Result:

The result is less heap allocation and GC activity when the PooledByteBufAllocator is used (which is the default)

Fixes #11890

Signed-off-by: Daniel Ferstay [email protected]

Motivation:

Previously, when the input ByteBuf was not heap allocated we copied the
input into a new byte array allocated on the heap for every encode() call.
This puts high-throughput clients that use the JdkZlibEncoder under memory
pressure.

Modifications:

Now, when the input ByteBuf is not heap allocated we copy the input into a
heap ByteBuf allocated from the PooledByteBufAllocator, releasing it after
the encode() has completed.

Result:

The result is less heap allocation and GC activity.

Fixes netty#11890

Signed-off-by: Daniel Ferstay <[email protected]>
@dferstay
Copy link
Contributor Author

dferstay commented Dec 4, 2021

Below is a memory profile before the change.

jdkzlibencoder_heap_alloc

@dferstay
Copy link
Contributor Author

dferstay commented Dec 4, 2021

After the change JdkZlibEncoder.encode is not burning so bright.

jdkzlibencoder_pooled_heap_alloc

// skip all bytes as we will consume all of them
uncompressed.skipBytes(len);
} else {
heapBuf = PooledByteBufAllocator.DEFAULT.heapBuffer(len, len);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
heapBuf = PooledByteBufAllocator.DEFAULT.heapBuffer(len, len);
heapBuf = ctx.alloc().heapBuffer(len, len);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you; done.

// We did not consume everything but the buffer is not writable anymore. Increase the capacity to
// make more room.
out.ensureWritable(out.writerIndex());
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please revert the formatting changes.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@normanmaurer ,
Are you referring to the additional indentation? If so, it is due to the addition of the try / finally block to ensure that the allocated heapBuf is released on method return. Do do you want me to remove the try / finally?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check the checkstyle errors

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it; the checkstyle errors should now be addressed.

writeHeader = false;
if (wrapper == ZlibWrapper.GZIP) {
out.writeBytes(gzipHeader);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please revert formatting changes

}
if (wrapper == ZlibWrapper.GZIP) {
crc.update(inAry, offset, len);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please revert formatting changes

uncompressed.readBytes(inAry);
offset = 0;
}
ByteBuf heapBuf = null;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make this final and assign in the if / else blocks

Copy link
Contributor Author

@dferstay dferstay Dec 6, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@normanmaurer ,

make this final and assign in the if / else blocks

I introduced a try / finally so that we would not leak the reference to the allocated heap buffer; this accounts for the formatting changes above and it also confuses the Java compiler when making heapBuf final; see attached screenshot.
Screenshot from 2021-12-06 10-00-16

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

got it...

@normanmaurer
Copy link
Member

Also please sign or ICLA: https://netty.io/s/icla

@dferstay
Copy link
Contributor Author

dferstay commented Dec 6, 2021

Also please sign or ICLA: https://netty.io/s/icla

Signed :)

@normanmaurer
Copy link
Member

@dferstay can you please revert the formatting changes ?

@normanmaurer normanmaurer changed the title JdkZlibEncoder uses pooled heap buffers for deflater input JdkZlibEncoder can use pooled heap buffers for deflater input Dec 8, 2021
@normanmaurer normanmaurer merged commit d80a34e into netty:4.1 Dec 8, 2021
@normanmaurer
Copy link
Member

@dferstay thanks a lot ! Would be cool if you can add details to the adopters page: https://netty.io/wiki/adopters.html

@normanmaurer normanmaurer added this to the 4.1.71.Final milestone Dec 8, 2021
@dferstay
Copy link
Contributor Author

dferstay commented Dec 8, 2021

@dferstay thanks a lot ! Would be cool if you can add details to the adopters page: https://netty.io/wiki/adopters.html

@normanmaurer,
Cheers; will do! 👍

laosijikaichele pushed a commit to laosijikaichele/netty that referenced this pull request Dec 16, 2021
…11891)


Motivation:

Previously, when the input ByteBuf was not heap allocated we copied the
input into a new byte array allocated on the heap for every encode() call.
This puts high-throughput clients that use the JdkZlibEncoder under memory
pressure.

Modifications:

Now, when the input ByteBuf is not heap allocated we copy the input into a
heap ByteBuf allocated from the configured ByteBufAllocator (which might be pooled), releasing it after
the encode() has completed.

Result:

The result is less heap allocation and GC activity when the PooledByteBufAllocator is used (which is the default)

Fixes netty#11890

Signed-off-by: Daniel Ferstay <[email protected]>
Co-authored-by: Daniel Ferstay <[email protected]>
Co-authored-by: Norman Maurer <[email protected]>
laosijikaichele pushed a commit to laosijikaichele/netty that referenced this pull request Dec 16, 2021
…11891)


Motivation:

Previously, when the input ByteBuf was not heap allocated we copied the
input into a new byte array allocated on the heap for every encode() call.
This puts high-throughput clients that use the JdkZlibEncoder under memory
pressure.

Modifications:

Now, when the input ByteBuf is not heap allocated we copy the input into a
heap ByteBuf allocated from the configured ByteBufAllocator (which might be pooled), releasing it after
the encode() has completed.

Result:

The result is less heap allocation and GC activity when the PooledByteBufAllocator is used (which is the default)

Fixes netty#11890

Signed-off-by: Daniel Ferstay <[email protected]>
Co-authored-by: Daniel Ferstay <[email protected]>
Co-authored-by: Norman Maurer <[email protected]>
10brothers pushed a commit to 10brothers/netty that referenced this pull request Jan 20, 2022
…11891)


Motivation:

Previously, when the input ByteBuf was not heap allocated we copied the
input into a new byte array allocated on the heap for every encode() call.
This puts high-throughput clients that use the JdkZlibEncoder under memory
pressure.

Modifications:

Now, when the input ByteBuf is not heap allocated we copy the input into a
heap ByteBuf allocated from the configured ByteBufAllocator (which might be pooled), releasing it after
the encode() has completed.

Result:

The result is less heap allocation and GC activity when the PooledByteBufAllocator is used (which is the default)

Fixes netty#11890

Signed-off-by: Daniel Ferstay <[email protected]>
Co-authored-by: Daniel Ferstay <[email protected]>
Co-authored-by: Norman Maurer <[email protected]>
raidyue pushed a commit to raidyue/netty that referenced this pull request Jul 8, 2022
…11891)


Motivation:

Previously, when the input ByteBuf was not heap allocated we copied the
input into a new byte array allocated on the heap for every encode() call.
This puts high-throughput clients that use the JdkZlibEncoder under memory
pressure.

Modifications:

Now, when the input ByteBuf is not heap allocated we copy the input into a
heap ByteBuf allocated from the configured ByteBufAllocator (which might be pooled), releasing it after
the encode() has completed.

Result:

The result is less heap allocation and GC activity when the PooledByteBufAllocator is used (which is the default)

Fixes netty#11890

Signed-off-by: Daniel Ferstay <[email protected]>
Co-authored-by: Daniel Ferstay <[email protected]>
Co-authored-by: Norman Maurer <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

JdkZlibEncoder: heap allocated arrays for deflater input generate memory pressure under load

2 participants