New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Re-add pooled sliced buffers? #4333
Comments
not to mention the composite buffers :D but I could live without them Oops, closed the issue. is it really that complicated to properly release them in case the original buffer is an input stream and the slice is made at decoder, fired through the pipeline and later slice.release()d by handler? I think I can see your point @Scottmitch so how about having two refcnt counters at slices so one of them would just increase the original refcnt and the second one would be dedicated to deciding when to recycle the slice? I hope I am not complicating too much. |
@ninja- - I considered fixing the pooling code for derived buffers but it boiled down to having feedback from the That lead me to take the "easier" path which was to pull it out because it was not functioning as originally intended. Can you explain why |
Well whether replacing most copy()s with slice() is a premature optimization is an another topic. But what I mean by copy is, well, I forgot to mention that I am not using directly copy().
here's the "copy" as copy() would also use unpooled buffers or something like that. So using slices avoids memory copies at frame decoder level but would come at a cost of trashing the memory with garbage as there is no pooling. For each single packet read, garbage. And I worked quite hard to pool everything so that the number of garbage it creates during I/O is an exact 0. IMO that's the behaviour we could use:
But I think that could break things...we need to think about it again knowing that the slices are usually made out of the input stream. |
@ninja- - If you can make it work without API changes or change in expected behavior then that would be good :) Also be sure to consider the case where there are slice objects of other slice objects. |
@Scottmitch what do you think about the proposed model? the part when I mention that it's hard not to break buf.slice().copy()? Actually the slices now aren't increasing the original refCnt...hmmm :/ |
@Scottmitch @normanmaurer ok I see now how it worked. I have an idea how to re-add it, but under another function like rslice() while slice() would stay without ref-counting. |
ok I think I got it...the class structure is quite ugly but it works. basically the derived buffer is refCnted by default and UnpooledSlicedByteBuf contains erasure for refCnting that forwards to parent. PooledSlicedByteBuf extends directly over AbstractSlicedByteBuf I implemented this with ~ 1000 lines of diff, will PR to review... under rslice() as well as rduplicate() also readRefSlice |
@normanmaurer @Scottmitch fyi https://github.com/ninja-/netty/commits/ninja |
Motivation: Pooling ByteBufs for slice / duplicate operations can miminize object creation a lot. We should try to pool these if possible. Modifications: - Add new overloaded operations to ByteBuf that can be used to obtain a retained slice or duplicate. These can be pooled internally as optimization. - Use optimized version in codecs. Result: Less object creation when using PooledByteBufAllocator.
Motivation: Pooling ByteBufs for slice / duplicate operations can miminize object creation a lot. We should try to pool these if possible. Modifications: Add new overloaded operations to ByteBuf that can be used to obtain a retained slice or duplicate. These can be pooled internally as optimization. Use optimized version in codecs. Result: Less object creation when using PooledByteBufAllocator.
Related: #4333 #4421 Motivation: slice(), duplicate() and readSlice() currently create a non-recyclable derived buffer instance. Under heavy load, an application that creates a lot of derived buffers can put the garbage collector under pressure. Modifications: - Deprecate the old derived buffer implementations - Add the new recyclable derived buffer implementations, which has its own reference count value - When a derived buffer is created, its internal reference count is 0. - When retain() is called on a derived buffer, the internal reference count becomes a positive value and the original buffer's retain() is called. - When release() is called on a derived buffer, the internal reference count is decreased first, and then the original buffer's release() is called when the internal reference count is 0. - Add ByteBufUtil.duplicate/slice() so that a user can easily implement ByteBuf.duplicate/slice() - Add missing overrides in some ByteBuf impls - Fix incorrect range checks in SlicedByteBuf - Miscellaneous: - Merge Duplicated/SlicedAbstractByteBuf.unwrap0() into unwrap() using covariant return type Result: - Derived buffers are now recycled when retained and released, although they are not recycled if a user called release() against the original buffer. buf.slice().retain().release(); // recycled buf.slice().retain(); buf.release(); // not recycled - Correct range checks in SlicedByteBuf
Related: #4333 #4421 Motivation: slice(), duplicate() and readSlice() currently create a non-recyclable derived buffer instance. Under heavy load, an application that creates a lot of derived buffers can put the garbage collector under pressure. Modifications: - Deprecate the old derived buffer implementations - Add the new recyclable derived buffer implementations, which has its own reference count value - When a derived buffer is created, its internal reference count is 0. - When retain() is called on a derived buffer, the internal reference count becomes a positive value and the original buffer's retain() is called. - When release() is called on a derived buffer, the internal reference count is decreased first, and then the original buffer's release() is called when the internal reference count is 0. - Add ByteBufUtil.duplicate/slice() so that a user can easily implement ByteBuf.duplicate/slice() - Add missing overrides in some ByteBuf impls - Fix incorrect range checks in SlicedByteBuf - Miscellaneous: - Merge Duplicated/SlicedAbstractByteBuf.unwrap0() into unwrap() using covariant return type Result: - Derived buffers are now recycled when retained and released, although they are not recycled if a user called release() against the original buffer. buf.slice().retain().release(); // recycled buf.slice().retain(); buf.release(); // not recycled - Correct range checks in SlicedByteBuf
Related: #4333 #4421 #5128 Motivation: slice(), duplicate() and readSlice() currently create a non-recyclable derived buffer instance. Under heavy load, an application that creates a lot of derived buffers can put the garbage collector under pressure. Modifications: - Add the new recyclable derived buffer implementations, which has its own reference count value - Add ByteBufUtil.duplicateRetained/sliceRetained() so that a user can easily implement ByteBuf.duplicateRetained/sliceRetained() - Use duplicateRetained() and sliceRetained() wherever possible Result: Derived buffers are now recycled when created via sliceRetained() and duplicateRetained()
Related: #4333 #4421 #5128 Motivation: slice(), duplicate() and readSlice() currently create a non-recyclable derived buffer instance. Under heavy load, an application that creates a lot of derived buffers can put the garbage collector under pressure. Modifications: - Add ByteBuf.rslice/rduplicate/readRSlice() which creates a non-recyclable derived buffer - Add the new recyclable derived buffer implementations, which has its own reference count value - Add ByteBufUtil.rduplicate/rslice() so that a user can easily implement ByteBuf.rduplicate/rslice() - Add ByteBufHolder.rduplicate() - Add a new protected method DefaultByteBufHolder.copy(ByteBuf) so that a user can implement copy/duplicate/rduplicate() easily - Use rduplicate() and rslice() wherever possible Result: Derived buffers are now recycled when created via rslice() and rduplicate()
Related: #4333 #4421 #5128 Motivation: slice(), duplicate() and readSlice() currently create a non-recyclable derived buffer instance. Under heavy load, an application that creates a lot of derived buffers can put the garbage collector under pressure. Modifications: - Add the following methods which creates a non-recyclable derived buffer - retainedSlice() - retainedDuplicate() - readRetainedSlice() - Add the new recyclable derived buffer implementations, which has its own reference count value - Add ByteBufUtil.retainedSlice() and retainedDuplicate() so that a user can implement the new ByteBuf methods easily - Add ByteBufHolder.retainedDuplicate() - Add ByteBufHolder.replace(ByteBuf) so that.. - a user can replace the content of the holder in a consistent way - copy/duplicate/retainedDuplicate() can delegate the holder construction to replace(ByteBuf) - Use retainedDuplicate() and retainedSlice() wherever possible - Miscellaneous: - Rename DuplicateByteBufTest to DuplicatedByteBufTest (missing 'D') Result: Derived buffers are now recycled when created via retainedSlice() and retainedDuplicate()
Related: #4333 #4421 #5128 Motivation: slice(), duplicate() and readSlice() currently create a non-recyclable derived buffer instance. Under heavy load, an application that creates a lot of derived buffers can put the garbage collector under pressure. Modifications: - Add the following methods which creates a non-recyclable derived buffer - retainedSlice() - retainedDuplicate() - readRetainedSlice() - Add the new recyclable derived buffer implementations, which has its own reference count value - Add ByteBufUtil.retainedSlice() and retainedDuplicate() so that a user can implement the new ByteBuf methods easily - Add ByteBufHolder.retainedDuplicate() - Add ByteBufHolder.replace(ByteBuf) so that.. - a user can replace the content of the holder in a consistent way - copy/duplicate/retainedDuplicate() can delegate the holder construction to replace(ByteBuf) - Use retainedDuplicate() and retainedSlice() wherever possible - Miscellaneous: - Rename DuplicateByteBufTest to DuplicatedByteBufTest (missing 'D') Result: Derived buffers are now recycled when created via retainedSlice() and retainedDuplicate()
Related: #4333 #4421 #5128 Motivation: slice(), duplicate() and readSlice() currently create a non-recyclable derived buffer instance. Under heavy load, an application that creates a lot of derived buffers can put the garbage collector under pressure. Modifications: - Add the following methods which creates a non-recyclable derived buffer - retainedSlice() - retainedDuplicate() - readRetainedSlice() - Add the new recyclable derived buffer implementations, which has its own reference count value - Add ByteBufUtil.retainedSlice() and retainedDuplicate() so that a user can implement the new ByteBuf methods easily - Add ByteBufHolder.retainedDuplicate() - Add ByteBufHolder.replace(ByteBuf) so that.. - a user can replace the content of the holder in a consistent way - copy/duplicate/retainedDuplicate() can delegate the holder construction to replace(ByteBuf) - Use retainedDuplicate() and retainedSlice() wherever possible - Miscellaneous: - Rename DuplicateByteBufTest to DuplicatedByteBufTest (missing 'D') Result: Derived buffers are now recycled when created via retainedSlice() and retainedDuplicate() and derived from a pooled buffer
Related: #4333 #4421 #5128 Motivation: slice(), duplicate() and readSlice() currently create a non-recyclable derived buffer instance. Under heavy load, an application that creates a lot of derived buffers can put the garbage collector under pressure. Modifications: - Add the following methods which creates a non-recyclable derived buffer - retainedSlice() - retainedDuplicate() - readRetainedSlice() - Add the new recyclable derived buffer implementations, which has its own reference count value - Add ByteBufHolder.retainedDuplicate() - Add ByteBufHolder.replace(ByteBuf) so that.. - a user can replace the content of the holder in a consistent way - copy/duplicate/retainedDuplicate() can delegate the holder construction to replace(ByteBuf) - Use retainedDuplicate() and retainedSlice() wherever possible - Miscellaneous: - Rename DuplicateByteBufTest to DuplicatedByteBufTest (missing 'D') Result: Derived buffers are now recycled when created via retainedSlice() and retainedDuplicate() and derived from a pooled buffer
Related: #4333 #4421 #5128 Motivation: slice(), duplicate() and readSlice() currently create a non-recyclable derived buffer instance. Under heavy load, an application that creates a lot of derived buffers can put the garbage collector under pressure. Modifications: - Add the following methods which creates a non-recyclable derived buffer - retainedSlice() - retainedDuplicate() - readRetainedSlice() - Add the new recyclable derived buffer implementations, which has its own reference count value - Add ByteBufHolder.retainedDuplicate() - Add ByteBufHolder.replace(ByteBuf) so that.. - a user can replace the content of the holder in a consistent way - copy/duplicate/retainedDuplicate() can delegate the holder construction to replace(ByteBuf) - Use retainedDuplicate() and retainedSlice() wherever possible - Miscellaneous: - Rename DuplicateByteBufTest to DuplicatedByteBufTest (missing 'D') - Make ReplayingDecoderByteBuf.reject() return an exception instead of throwing it so that its callers don't need to add dummy return statement Result: Derived buffers are now recycled when created via retainedSlice() and retainedDuplicate() and derived from a pooled buffer
Related: #4333 #4421 #5128 Motivation: slice(), duplicate() and readSlice() currently create a non-recyclable derived buffer instance. Under heavy load, an application that creates a lot of derived buffers can put the garbage collector under pressure. Modifications: - Add the following methods which creates a non-recyclable derived buffer - retainedSlice() - retainedDuplicate() - readRetainedSlice() - Add the new recyclable derived buffer implementations, which has its own reference count value - Add ByteBufHolder.retainedDuplicate() - Add ByteBufHolder.replace(ByteBuf) so that.. - a user can replace the content of the holder in a consistent way - copy/duplicate/retainedDuplicate() can delegate the holder construction to replace(ByteBuf) - Use retainedDuplicate() and retainedSlice() wherever possible - Miscellaneous: - Rename DuplicateByteBufTest to DuplicatedByteBufTest (missing 'D') - Make ReplayingDecoderByteBuf.reject() return an exception instead of throwing it so that its callers don't need to add dummy return statement Result: Derived buffers are now recycled when created via retainedSlice() and retainedDuplicate() and derived from a pooled buffer
Fixed by #5144 |
77ff24b has deleted the sliced pooled buffer.
@Scottmitch could you re-evaluate this decision. I really liked using slices here and there but I got rid of them to reduce garbage creation after this was reverted.
I am aiming to get rid of copy() etc. again and have another strategy for rewriting packets that would need to expand the buffer.
So instead of operating on a copy
Original (a copy from stream):
-> AAA BBB CCC
rewrite into
-> AAA DDDD CCC
Aiming to do something like this if only the slices are to be recycled again:
Original:
-> AAA BBB CCC
Send:
The text was updated successfully, but these errors were encountered: