-
Notifications
You must be signed in to change notification settings - Fork 210
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
json.Marshal
allocates a lot of unnecessary memory
#324
Comments
Couldn't you do the opposite as func (h *Header) MarshalNextJSON(opts jsonv2.MarshalOptions, enc *jsonv2.Encoder) error {
// TODO: This mutates h.Extensions, which may be unacceptable.
// Might need to clone the map if there are unsanitized keys.
// or maybe we don't care for marshaling purposes?
h.Extensions.sanitize()
if len(h.Extensions) == 0 {
h.Extensions = nil
}
var x struct {
CommonValidations
SimpleSchema
Extensions
HeaderProps
} {
CommonValidations: h.CommonValidations,
SimpleSchema: h.SimpleSchema,
Extensions: h.Extensions,
HeaderProps: h.HeaderProps,
}
return opts.MarshalNext(enc, &x)
} |
For |
If I recall most of them were fine. Which type wasn't? |
That's unfortunate. It seems that the only reason why How about? func (o *Operation) MarshalNextJSON(opts jsonv2.MarshalOptions, enc *jsonv2.Encoder) error {
// TODO: Should this be done?
x.Extensions.sanitize()
if len(x.Extensions) == 0 {
x.Extensions = nil
}
// OperationPropsAlt is identical to OperationProps,
// but lacks a MarshalJSON method and
// uses `omitzero` instead of `omitempty` on the
// Security and Deprecated fields.
type OperationPropsAlt struct {
Description string `json:"description,omitempty"`
Consumes []string `json:"consumes,omitempty"`
Produces []string `json:"produces,omitempty"`
Schemes []string `json:"schemes,omitempty"`
Tags []string `json:"tags,omitempty"`
Summary string `json:"summary,omitempty"`
ExternalDocs *ExternalDocumentation `json:"externalDocs,omitempty"`
ID string `json:"operationId,omitempty"`
Deprecated bool `json:"deprecated,omitzero"`
Security []map[string][]string `json:"security,omitzero"`
Parameters []Parameter `json:"parameters,omitempty"`
Responses *Responses `json:"responses,omitempty"`
}
x := struct {
Extensions
*OperationPropsAlt
}{
Extension: o.Extensions,
OperationPropsAlt: (*OperationPropsAlt)(&o.OperationProps), // see https://go.dev/issue/16085
}
return opts.MarshalNext(enc, &x)
} See https://pkg.go.dev/github.com/go-json-experiment/json#hdr-JSON_Representation_of_Go_structs for the semantics of |
It's unfortunate that we need to declare the |
The Kubernetes project currently lacks enough contributors to adequately respond to all issues and PRs. This bot triages issues and PRs according to the following rules:
You can:
Please send feedback to sig-contributor-experience at kubernetes/community. /lifecycle stale |
/remove-lifecycle stale |
FYI, there's been some upstream activity that may help you. We added That said, there's been a few breaking changes at HEAD:
Summary of breaking changes:
This will remove the need for gross hacks like this: kube-openapi/pkg/validation/spec/schema.go Lines 201 to 237 in d090da1
|
That's awesome, thanks Joe for the update! I'm pretty excited about removing all these ugly type declaration :-) |
This is a follow-up of #315/#319. Now that
Unmarshaling
has been fixed, we need to worry about the next big thing,Marshaling
.As we can see from the pprof heap profile (alloc_space) below,
json.Marshal
is allocating a lot of memory, certainly because it serializes in buffers that are quickly discarded as these buffers are "concatenated" (e.g. https://github.com/kubernetes/kube-openapi/blob/master/pkg/validation/spec/header.go#L44-L63, https://github.com/kubernetes/kube-openapi/blob/master/pkg/validation/spec/schema.go#L435-L466)There's clearly no great way to do that with json.Marshal v1, since when you have multiple embedded types (which we have everywhere in the spec), only one of the custom marshaller is called. That's also true for json.Marshal v2, I don't see how it could be different anyways.
I've been looking at go-json-experiment, but I can't find a good way to "embed" multiple values, all the methods require that you serialize exactly one json "value", but in most cases, we want to serialize a list of fields for each of these embedded sub-structures. I think we could give each of these types a "MarshalKeysAndValues", and construct the object itself, but then we will have to rewrite a lot of logic to extract the keys and values.
Anyways, I'm stuck. Suggestions welcome @dsnet @alexzielenski @liggitt
The text was updated successfully, but these errors were encountered: