This tallies with what I saw: of the allocations that caused a spill, 2846 were of 120 bytes and 5692 were of 352 bytes. Those were the only sizes. floor(4000/352) = 11, and 65535/11 = 5958. 

What kind of self-tuning are you imagining? Just something we run ourselves, and use to update a constant that is built into our code? Or actually writing something to disk on each startup, and using that to guide the next? The former isn't fully automatic, but the latter seems overkill and doesn't directly solve the UT startup problem that motivated this in the first place.