It’s a lot like a filesystem in some ways: it keeps structures that help it figure out which memory in its pool is free, mappings between tables and query results, query text and the query results.
Consequently, when it begins caching the result set, the server has no way of knowing how large it will eventually be.
When the result is finished, if there is space left in the last block the server trims it to size and merges the leftover space into the adjacent free block.
In other words, the MYSQL server manages its own memory its own memory; it does not rely on the operating system to do it.
Trimming the results can leave a free block that’s smaller than query_cache_min_res_unit and cannot be used for storing future cache results.
Trimming the first result to size left a gap between the two results, a block too small to use for storing a different query result.