For the input in your code sample, on top of being references by the python variable called “input”, the Tensor is already referenced in the computational graph (because it is needed for the backward computation). And that computational graph is kept alive by output that references it.
So the Tensor cannot be freed until output goes out of scope.
Note that if you call backward() on that graph (with retain_graph=False, the default), then it will free up the graph and that reference to input will go away. And so input should get deallocated, on the next iteration, as soon as the “input” python variable is overwritten.