bufferedPayload must span multiple MySQL rows, need to re-work buffering. ArrayPool.Shared.Rent/Return may be overkill here as it seems to like to allocate a power of 2, we should probably switch this to allocating the correct sized objects.
The text was updated successfully, but these errors were encountered:
As a bit of a postmortem, I'm fairly sure that the sequence of events that read to this bug were:
Buffering Rows was initially written into #136, but at that time socket reads were not buffered, so the only data in m_buffer pertained to the current row.
Socket reads were adjusted to be buffered in #167, which meant that m_buffer could now contain more than one MySQL row
I did not catch the high memory usage when implementing BufferResultSets#204
Most people using this library will use the default BufferResultSets=false and never encounter this bug. The exception is users of Pomelo.EntityFramework.MySql, which sets it to true.
The effects of this bug are that memory usage per row read from MySQL will often be 16384 bytes instead of whatever storage the row would take normally. This means that if the row would only normally be 16 bytes, memory usage would be 1,024 times higher than it should.
If all rows are read from the buffered result set, then memory would be returned properly. This bug becomes a really big issue if several thousand rows are read. For example, 62,500 rows being read would cause the reader to consume 1GB of memory before it was available for consumption so that memory could be freed.
Originally reported at PomeloFoundation/Pomelo.EntityFrameworkCore.MySql#262
Here are the actual allocations by ArrayPool.Shared.Rent/Return:
bufferedPayload
must span multiple MySQL rows, need to re-work buffering. ArrayPool.Shared.Rent/Return may be overkill here as it seems to like to allocate a power of 2, we should probably switch this to allocating the correct sized objects.The text was updated successfully, but these errors were encountered: