It is a shorthand way of declaring an implementation of the generic class Nullable, where T is a non-nullable value type.
So
int? i = null;
is the same as
Nullable i = null;
As mentioned above Nullable exposes the HasValue property so you can check if i has a value before working on it.
Interesting to note: If you cast Nullable i = 3; to an object, you can cast back to an int or a Nullable because it had a value before boxing. If, however you cast Nullable i = null; to an object you will get a NullReferenceException when casting back to an int but you can cast back to a Nullable.