OCaml's internals benefit, in particular, from the GC needing very little layout information. All non-conservative GCs need to know what's a pointer and what isn't. Many languages, from Java to Haskell, associate this info, at runtime, with each heap object (and stack frame!). This is actually done quite elegantly in Haskell (stack frames and thunks are structurally equivalent: returning from a function is effectively popping a thunk of the stack and tail-calling it). Java's design, as a language, is constrained by this. For example, you cannot use a primitive in a type parameter for a generic for this reason.
OCaml doesn't need this, although every heap object is still tagged (for various reasons) and stores the size in the header. The OCaml GC can tell what's what by just inspecting the value itself (and some block tags imply no-follow, like float array, string, opaque, etc). In effect, OCaml's distinction between primitives (value itself passed around in machine word) and non-primitives (pointer to block passed around in machine word) is invisible to the programmer.
Also unlike Haskell and Java (not to say there's much in common with these two, but goes to show how OCaml's implementation differs from those of a wide spectrum of languages), very little type information is stored in the tag.
FWIW, there's a good overview of the garbage collector and the rationale behind several design decisions in _Developing Applications with Objective Caml_ (free English translation: http://caml.inria.fr/pub/docs/oreilly-book/). The book is a few versions old, but it's one of the better overall guides to OCaml I've seen.
I've enjoyed these first two - they're a good summary of how things are laid out, without getting into too many of the messy details. I miss an explanation of closures, but that'd require lots of messy details, I'm sure.
OCaml doesn't need this, although every heap object is still tagged (for various reasons) and stores the size in the header. The OCaml GC can tell what's what by just inspecting the value itself (and some block tags imply no-follow, like float array, string, opaque, etc). In effect, OCaml's distinction between primitives (value itself passed around in machine word) and non-primitives (pointer to block passed around in machine word) is invisible to the programmer.
Also unlike Haskell and Java (not to say there's much in common with these two, but goes to show how OCaml's implementation differs from those of a wide spectrum of languages), very little type information is stored in the tag.