A pinned object is one that cannot be moved around by the garbage collector, meaning its address has to be kept the same because someone else, usually some piece of non managed code, depends upon the object being at a definite memory address.
Usually the garbage collector has freedom to relocate objects in memory. In managed code, as the garbage collector has the ability to access all references, it can freely remap an object to a different location and then update all references to that object so that the process is transparent to the running code. That way, the GC has the ability to better organize the program's memory and compact it if needed.
When an non-managed object is interacting with your code (in unsafe sections,) a situation may arise where there's a pointer somewhere to a piece of your code — for example, to a piece of memory addressed in your code that is being handled by an external COM call. This memory can't be remapped because the COM call is expecting the object to be in a given address and thus, if it was moved, the GC wouldn't have any way to notify the COM object of that change, resulting in an access violation or worse.