-
-
Notifications
You must be signed in to change notification settings - Fork 795
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
Can BufferRecycler support a fixed buffer size which can be customized, instead of dynamic one by calling _allocMore() #833
Comments
Unfortunately due to the way I'll leave this open and see if something could be figured out. |
@cowtowncoder I found that when releasing space to BufferRecycler, comparing the size of the current space with the original space(recorded in an array at each allocation) can solve the problem. Could you help confirm whether the following codes are correct?
This ensures that if the newly created buffer length is less than or equal to the original, it will not be updated. I think this can reduce the number of buffer objects promoted to the old generation space to some extent. |
@qiuyinglanshan I think I understand the idea and it makes sense (try to avoid replacing buffer with something that's not bigger than what we already had). But I do not like storing an additional reference in separate array. I'll see if I can provide a simple alternative that does this. |
Oh actually, no, never mind. I forgot that the buffer reference is cleared when returned with So with this I am not sure why change you suggest would make any difference. I am not sure I understand the logic after all. |
Yes, this is why I created a reference point to the original byte array instead of comparing sizes directly.
I'll try to show the difference between the original logic and the new logic. First of all, I want to explain that because _byteBuffers is held by ThreadLocal for a long time (eg. in thread pool case), and the array object it references will be promoted to the old age. When releaseByteBuffer() is called, _byteBuffers may refer to a new array object if _allocMore() is executed. Although with the occurrence of younggc for many times(eg. max 15 age), this new object has not been recycled since ThreadLocal holding. As a result, the new array object will continue to promoted the old generation space. My new logic is to hope that the new array object can be recycled by younggc if its length less than or equal to the original buffer arrry(In many cases, both of the length are 128k). So it reduce the number of buffer objects promoted to the old generation space, and fullgc occurs less frequently. |
In addition, as you mentioned in #835 , I think it would be better to add an initial buffer size that can be configured instead of "{ 8000, 8000, 2000, 2000 }". |
+1 for configurability, created #835 for being able to configure As to change proposed, part I do not understand is why change would likely change things: On change proposed, I think there is a real correctness problem for async use cases where same thread may be used to serve multiple requests. If so, when a buffer is returned we can NOT be certain that all buffers returned are freed (or more specifically, most recently returned buffer has been freed). So I think making change could cause data corruption where sometimes (rarely but sometimes) buffer could end up being used by 2 parsers/generators, from different sync handlers. I say this because originally reference to buffer was not actually cleared and we relied on assumption that calls are always one-thread-per-request blocking code. |
I'm sorry I can not understand it, and I'd appreciate it if you could point it out again.
According to the following code, when a buffer is borrowed, it will NOT be borrowed again by other requests until it is returned by the previous request. Therefore, the buffer(and more specifically, the index it is in) should be exclusive, so I cannot understand why it will NOT be freed by other requests when it is returned.
The newly added reference is actually an array of 4 references, with each element pointing to a unique buffer when it is borrowed. In the new logic, only the current index(variable
Looking forward to your guidance~ |
@qiuyinglanshan You are assuming that there will not be overlapping creation and usage of parsers and/or generators: this is not true for asynchronous frameworks -- or actually even in blocking ones, come to think of that. I don't think I want to proceed with approach suggested above. If the allocation churn is to be solved, it will require caller (parser, generator) to try to return what it seems is most optimal (biggest, or if multiple buffers with same size allocated, the one that is recycled). |
A lot of work went into 2.16 to allow pluggable recycler pools (see Closing this issue as it is probably outdated; if changes still desired, should file a new issue based on current state of things (wrt 2.17 branch). |
As _allocMore() method is called, _byteBuffers will reference to a new larger byte array, and the garbage collector has to collect the original memory. In my application, it may cause frequently fullgc.
The screenshot shows a dump with many unreachable byte array (in old heap) which caused by BufferRecycler.
When I switched USE_THREAD_LOCAL_FOR_BUFFER_RECYCLING to false, fullgc times reduced while younggc times increased, so I ask you if we can use bufferRecycler and with a fixed size buffer ?
The text was updated successfully, but these errors were encountered: