-
Notifications
You must be signed in to change notification settings - Fork 40.1k
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
Faster ExtractList. Add ExtractListWithAlloc variant. #113362
Faster ExtractList. Add ExtractListWithAlloc variant. #113362
Conversation
a80dd26
to
2b73ffa
Compare
I'm not convinced we should deep copy at all. But definitely it shouldn't go here, there are other callers of this code path than just the watch cache. |
Thank you for your suggestion ~ 😄 I find a more suitable place to add the relevant logic. |
2b73ffa
to
5dfcb42
Compare
/ping @lavalamp Hi @lavalamp . In order not to destroy the original ExtractList. I added ExtractWithAlloc. And instead of using DeepCopy, a shallow copy of the newly generated object is done by using reflect.New and reflect.Value.Set. The map and slice in the newly generated object will share the same memory space with the elements in the list. Only the basic types of golang fields such as int and string will allocate memory. After my tests, it can work well (unit tests are being written), and I hope to get some suggestions from you on the solution. grateful. |
This still double-allocates for some amount of time, it's too late. I'm actually not even convinced that deep copy is enough, are e.g. strings copied or are they still references to the original deserialized data? A correct fix is going to be very invasive, which is why I'm questioning that the benefit would be high enough. |
5dfcb42
to
101c195
Compare
Some clarifications are necessary here: Take type ConfigMapList struct {
....
Items []ConfigMap
}
type ConfigMap struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
....
Data map[string]string `json:"data,omitempty" protobuf:"bytes,2,rep,name=data"`
}
func (in *ConfigMap) DeepCopyObject() runtime.Object {
...
} Items elements are all ConfigMap, ConfigMap does not implement runtime.Object, (the receiver of the DeepCopyObject method is *ConfigMap), so we need to use *ConfigMap. The return value of our
Only the fields of the basic type (int, string... mentioned above) will be copied here, and the Data field will point to configMapList.Items[0].Data. When go-runtime executes the gc-routine, if configMapList.Items[0] has no related references. will be released. But since Data is referenced by ret.Data at the same time. This memory will not be freed.
This is because the following code exists in ExtractList: func ExtractList(obj runtime.Object) ([]runtime.Object, error) {
....
for i := range list {
raw := items.Index(i)
switch item := raw.Interface().(type) {
....
....
However, ExtractListWithAlloc determines the type by comparing raw.Type. When it is determined that the current Object is a ConfigMap, Alloc creates a new Configmap and assigns it a value. So it can not only guarantee the number of memory allocations, but also avoid directly referencing the Items list. |
101c195
to
b546958
Compare
…kUnstructured struct Signed-off-by: Chirayu Kapoor <[email protected]>
…kUnstructured struct Signed-off-by: Chirayu Kapoor <[email protected]>
…kUnstructured struct Signed-off-by: Chirayu Kapoor <[email protected]>
…kUnstructured struct Signed-off-by: Chirayu Kapoor <[email protected]>
…kUnstructured struct Signed-off-by: Chirayu Kapoor <[email protected]>
…kUnstructured struct Signed-off-by: Chirayu Kapoor <[email protected]>
…kUnstructured struct Signed-off-by: Chirayu Kapoor <[email protected]>
What type of PR is this?
What this PR does / why we need it:
Which issue(s) this PR fixes:
Fixes #113305
related: issue #102718
Special notes for your reviewer:
After the reflector obtains the ObjectList through ListAndWatch, it will obtain the Object list through ExtractList (internally obtain the list of objects through go-reflect) and store it in Indexer. Assuming that an Object in the List does not change (). Then the memory occupied by the entire ObjectList cannot be released. Although most of the data in this List is out of date.
We remove the dependency on ObjectList through Alloc && Set (ShallowCopy) on the object. Help golang runtime gc this section does not need to use memory.
Does this PR introduce a user-facing change?
Additional documentation e.g., KEPs (Kubernetes Enhancement Proposals), usage docs, etc.: