Proof of concept for Copy-on-Write implementation
An experiment to implement one of the proposals discussed in https://github.com/pandas-dev/pandas/issues/36195/, described in more detail in https://docs.google.com/document/d/1ZCQ9mx3LBMy-nhwRl33_jgcvWo9IWdEfxDNQ2thyTb0/edit

This PR adds Copy-on-Write (CoW) functionality to the DataFrame/Series when using ArrayManager. 
It does this by adding a new `.refs` attribute to the `ArrayManager` that, if populated, keeps a list of `weakref` references (one per columns, so `len(mgr.arrays) == len(mgr.refs)` to the array it is viewing. 
This ensures that if we are modifying an array of a child manager, we can check if it is referencing (viewing) another array, and if needed do a copy on write. And also if we are modifying an array of a parent manager, we can check if that array is being referenced by another array and if needed do a copy on write in this parent frame. (of course, a manager can both be parent and child at the same time, so those two checks always happen both)

A very brief summary of the behaviour you get (longer description at https://github.com/pandas-dev/pandas/issues/36195#issuecomment-786654449):

- *Any* subset (so also a slice, single column access, etc) uses CoW (or is already a copy)
- DataFrame methods that return a new DataFrame return shallow copies (using CoW) if applicable (for this POC I implemented that for `reset_index` and `rename` to test, needs to be expanded to other methods)

I added a `test_copy_on_write.py` which already tests a set of cases (which of course needs to be expanded), going through that file should give an idea of the kind of behaviours (and how it changes compared to current master/BlockManager). Link to that file in the diff: [click here](https://github.com/pandas-dev/pandas/pull/41878/files#diff-2abca9577897e44acf7b37c1412c9fc324b0464723cdf1d68a0f1467834a9245)

(I only added new, targeted tests in that file, I didn't yet start updating existing tests, as I imagine there will be quite a lot)

This is a proof-of-concept PR, so the feedback I am looking for / what I want to get out of it:

- A concrete starting point for an implementation, to stir the discussion on this topic https://github.com/pandas-dev/pandas/issues/36195/ (and a concrete implementation you can play with, to get feedback on the proposed semantics)
- Review of the actual implementation using `weakrefs` (it's quite simple at the moment, but not too simple? Will this be robust enough?)
- Other corner cases that should certainly be tested
- ...

And to be clear, not yet everything is covered (there are some `# TODO`'s in `array_manager.py`, but only fixing those while also adding tests that require it)

TODO:

- [ ] Series and DataFrame constructors

cc @pandas-dev/pandas-core 