I want to recycle the message object of protobuf to reduce GC consumption at runtime,but I'm not sure whether it's safe.The sample code for testing is as follows:
test.proto
message Hello{
uint32 id = 1;
}
test.pb.go
type Hello struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
ID uint32 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
}
func (x *Hello) Reset() {
*x = Hello{}
if protoimpl.UnsafeEnabled {
mi := &file_proto_login_api_login_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
// other codes
main.go
func main() {
// Disable GC to test re-acquire the same data
gc := debug.SetGCPercent(-1)
// As a protobuf object pool
cache := sync.Pool{New: func() interface{} { return &test.Hello{} }}
// Take out an object and use it
m1 := cache.Get().(*test.Hello)
m1.ID = 999
fmt.Println(&m1.ID) // print 999
// Empty the data and put it back into the object pool
m1.Reset()
cache.Put(m1)
// Take out an object again and use it
m2 := cache.Get().(*test.Hello)
fmt.Println(&m2.ID) // print 0
debug.SetGCPercent(gc)
}
CodePudding user response:
The code you show is safe. Pooling like this becomes "unsafe" when references to objects are held after they are put into the pool. You risk race conditions or strange bugs. So it also depends on the code that uses your objects.
The protocol buffers library and gRPC libraries don't hold on to references to protobuf objects, as far as I know. Doing so would break a lot of code since such libraries have no way of knowing when it would be safe to reuse.
So as long as you make sure that your own code doesn't use objects after they are put in the pool, you should be good.
