  We consider the sequential allocation of $m$ balls (jobs) into $n$ bins
(servers) by allowing each ball to choose from some bins sampled uniformly at
random. The goal is to maintain a small gap between the maximum load and the
average load. In this paper, we present a general framework that allows us to
analyze various allocation processes that slightly prefer allocating into
underloaded, as opposed to overloaded bins. Our analysis covers several natural
instances of processes, including:
  The Caching process (a.k.a. memory protocol) as studied by Mitzenmacher,
Prabhakar and Shah (2002): At each round we only take one bin sample, but we
also have access to a cache in which the most recently used bin is stored. We
place the ball into the least loaded of the two.
  The Packing process: At each round we only take one bin sample. If the load
is below some threshold (e.g., the average load), then we place as many balls
until the threshold is reached; otherwise, we place only one ball.
  The Twinning process: At each round, we only take one bin sample. If the load
is below some threshold, then we place two balls; otherwise, we place only one
ball.
  The Thinning process as recently studied by Feldheim and Gurel-Gurevich
(2021): At each round, we first take one bin sample. If its load is below some
threshold, we place one ball; otherwise, we place one ball into a
$\textit{second}$ bin sample.
  As we demonstrate, our general framework implies for all these processes a
gap of $\mathcal{O}(\log n)$ between the maximum load and average load, even
when an arbitrary number of balls $m \geq n$ are allocated (heavily loaded
case). Our analysis is inspired by a previous work of Peres, Talwar and Wieder
(2010) for the $(1+\beta)$-process, however here we rely on the interplay
between different potential functions to prove stabilization.
