io: Copy() unnecessarily allocates memory when src is a file and is empty #53658
Labels
NeedsInvestigation
Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Milestone
What version of Go are you using (
go version
)?Does this issue reproduce with the latest release?
Ye.
What operating system and processor architecture are you using (
go env
)?go env
OutputWhat did you do?
This affects
io.Copy()
when src is a file, and dst is a*net.TCPConn
.Here is a minimal benchmark: https://go.dev/play/p/zgZwpjUatSq
Benchmark with
go test -bench=. -benchmem
Summary is that a gorotoutine writes to a file, another goroutine reads from the file and writes it to a TCPConn with io.Copy(). io.Copy tries to be efficient and will try to use
sendfile(2)
, however it doesn't always succeed and ends up allocating a buffer anyway. In my deubgging it turns out the current logic believessendfile(2)
failed if we written 0 bytes. Using benchmark above one can see that we allocate 5KB/op, where op is writing a single byte.This also affects
io.CopyBuffer()
, when we fail to usesendfile(2)
(in case of empty src) it falls back toio.Copy(writerOnly{w}, r)
which ignores passed in buffer and allocates its own.What did you expect to see?
CopyBuffer
always uses passed in buffer,Copy
does not allocate extra buffer when src is empty.What did you see instead?
Running the benchmark above shows 5GB was allocated to transfer 0.5MB worth of data, due to allocating a buffer (see
size := 32 * 1024
below) when it wasn't necessary (sendfile(2)
tried to copy, but there was nothing to copy).The text was updated successfully, but these errors were encountered: