fine-grained locking for huge allocations (but not the default chunk allocator)

This does succeed in removing the huge allocation code as a bottleneck, but the default chunk allocator has a global lock so it only kills the serialization in the code paths that are not obtaining or releasing chunks like a no-op reallocation. The chosen hash function is quite bad, but the good hash function that's already in-tree is designed for strings and would be very expensive here.