An Ice object is an abstraction. Ice objects do not physically exist — there are no programming-language artifacts that would directly correspond to Ice objects, and the Ice run time does not track object existence.
The concept of an Ice object is made real by a servant, which is said to incarnate the Ice object. A servant is a programming-language object that implements the operations for an Ice object. The Ice run time sends invocations on an Ice object to the servant that incarnates the object. Note that an Ice object can exist even if no servant exists for it. For example, a server can use a servant locator to instantiate a servant for an incoming request on demand, and then destroy the servant again as soon as the request completes. In that case, the servant is destroyed, but the Ice object that was incarnated by the servant continues to exist. (Another request for the same Ice object would be sent to a new servant instance.) Note that this implies that Ice objects and servants have separate life cycles — they can be created and destroyed independently.
Each Ice object has an identity, known as the object identity. No two Ice objects can have the same identity. You establish the link between the conceptual Ice object and its servant when you add a servant for the Ice object to the Active Servant Map (ASM), for example, by calling
ObjectAdapter::add. Internally, this adds an entry to a table that is used to dispatch incoming requests: the identity is the key, and a pointer or reference to the servant is the lookup value. This allows the server-side run time to track which servant should handle a request for a particular Ice object. Often, each Ice object is represented by a different servant, so there is a one-to-one correspondence between Ice objects and servants. However, you can have a single servant incarnate multiple Ice objects (for example, by using a default servant).
A proxy is a handle that denotes a particular Ice object. You can think of a proxy as the equivalent of an object pointer, except that a proxy can denote an object in a remote address space, whereas a pointer can only point at an object in the local address space. A proxy contains the object identity of the Ice object it denotes. In addition, a proxy contains endpoint information that allows the client-side run time to find out where it can contact the server that contains the Ice object denoted by the proxy. When a client uses a proxy to invoke an operation on an Ice object, the Ice run time extracts the object identity from the proxy and sends it over the wire to the server. In turn, the server-side run time uses the object identity to locate the servant for the Ice object and, if a servant exists, dispatches the invocation to that servant.
In summary: an Ice object is a concept; a servant is the programming artifact that implements the concept, and a proxy is a handle that allows requests to be sent to the Ice object that is incarnated by the servant.