Both functions will consume the same amount of memory. The execution will look like this (in parenthesis you have current/peak memory usage in multiplies of A size):

Assume A is allocated (1/1)
Compute A**2 (2/2)
Compute 2*A (3/3)
Compute A**2 - 2*A (4/4)
Free A**2 and 2*A (2/4)
Compute torch.sqrt(B) (3/4)
Return and free everything except the input and result (2/4)

Nevertheless, it is good advice to try to minimize the number of local variables - the sooner things go out of scope the sooner the memory will be available for reuse (btw you can use del to free locals you don’t need).
There’s no way for the framework to know when a tensor won’t be needed anymore, we don’t have that knowledge upfront, abnd this is why it’s impossible to implement any garbage collection. The memory management is already very efficient and all tensors are freed as soon as you let them go.