Garbage collectable pinned arrays!

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Willy Denoyette [MVP]

    #16
    Re: Garbage collectable pinned arrays!

    "Ben Voigt [C++ MVP]" <rbv@nospam.nos pamwrote in message
    news:%23AkPUVmb IHA.1164@TK2MSF TNGP02.phx.gbl. ..
    >>That's not an unusual case. I've already given two examples of APIs
    >>in widespread use which require a buffer to stay in one position
    >>after the initial function call which accepts the pointer.
    >>>
    >>
    >True, but if you need this, why is the cost of pinning so important?
    >The cost of GCHandle.Alloc is ~5500 cycles. That means a one time
    >cost to pin a buffer that lives until the end of the process, if you
    >do this early in the process you won't suffer from fragmentation of
    >the gen0 heap as this object will end on the gen2 heap anyway.
    >
    That's what I do now.
    >
    But doesn't the object need to be moved to end up in gen2 data space?
    Won't the pinning reference prevent that?
    >
    No, but all depends on the sizes of the individual generations, that's why I
    say pin your buffers early in the process and after a GC.Collect().
    You can verify the location of your pinned buffer, by attaching to a native
    debugger like nsdb or windbg..
    Once attached, enter:
    !dumpheap -type <yourPinnedType >
    this returns the object's address (and some other info), something like:
    ....
    Address MT Size
    02721660 79131a68 1612
    ....

    To find the generation where your object "lives" , you'll have to compare
    it's address with the start address of the generations returned by:

    !eeheap -gc
    ....
    Number of GC Heaps: 1
    generation 0 starts at 0x0272d230
    generation 1 starts at 0x02721cac
    generation 2 starts at 0x02721000
    ....

    here the object at address 02721660 falls in the Gen2 range.
    Pinning an object that follows a couple of MB's of other live objects, has
    little chance to end on the Gen2, unless the GC can move the object to gen2
    at the moment of "pinning".

    >>
    >>
    >>>Also, you keep ignoring my remark that the fact that addresses of
    >>>*Large* objects are fixed is a convenience of the current version of
    >>>the CLR, nothing stops MS from changing this.
    >>>
    >>Which is why the OP is asking for a keyword / MSIL flag that will
    >>let the runtime know that the object is intended to be fixed for as
    >>long as it lives. It would be an implementation detail whether the
    >>memory is allocated from the LOH, OLE task allocator, etc, etc. Also I
    >>don't think that sacrificing GC for such objects would
    >>necessarily be a big loss, they either will live to the end of the
    >>process anyway, or they can be explicitly freed.
    >>>
    >>
    >But , this is what "fixed" is meant for, sure, it's scope is limited
    >by it's containing function scope, but you can perfectly pin an
    >object across several unmanaged function calls.
    >
    But it needs an "unsafe" block, for no apparent reason.
    "unsafe" blocks are needed when using pointers!
    This produces non-verifiable code, so no surprises here, you are warned.....

    Willy.

    Comment

    • Ben Voigt [C++ MVP]

      #17
      Re: Garbage collectable pinned arrays!

      Willy Denoyette [MVP] wrote:
      "Ben Voigt [C++ MVP]" <rbv@nospam.nos pamwrote in message
      news:%23AkPUVmb IHA.1164@TK2MSF TNGP02.phx.gbl. ..
      >>>That's not an unusual case. I've already given two examples of
      >>>APIs in widespread use which require a buffer to stay in one
      >>>position after the initial function call which accepts the pointer.
      >>>>
      >>>
      >>True, but if you need this, why is the cost of pinning so important?
      >>The cost of GCHandle.Alloc is ~5500 cycles. That means a one time
      >>cost to pin a buffer that lives until the end of the process, if you
      >>do this early in the process you won't suffer from fragmentation of
      >>the gen0 heap as this object will end on the gen2 heap anyway.
      >>
      >That's what I do now.
      >>
      >But doesn't the object need to be moved to end up in gen2 data space?
      >Won't the pinning reference prevent that?
      >>
      >
      No, but all depends on the sizes of the individual generations,
      that's why I say pin your buffers early in the process and after a
      GC.Collect(). You can verify the location of your pinned buffer, by
      attaching to a
      native debugger like nsdb or windbg..
      Once attached, enter:
      !dumpheap -type <yourPinnedType >
      this returns the object's address (and some other info), something
      like: ...
      Address MT Size
      02721660 79131a68 1612
      ...
      >
      To find the generation where your object "lives" , you'll have to
      compare it's address with the start address of the generations
      returned by:
      !eeheap -gc
      ...
      Number of GC Heaps: 1
      generation 0 starts at 0x0272d230
      generation 1 starts at 0x02721cac
      generation 2 starts at 0x02721000
      ...
      >
      here the object at address 02721660 falls in the Gen2 range.
      Pinning an object that follows a couple of MB's of other live
      objects, has little chance to end on the Gen2, unless the GC can move
      the object to gen2 at the moment of "pinning".
      Ok, so changing the generation of an object is done by moving the generation
      boundary in memory, not by actually changing the object's address. I guess
      that makes good sense.
      >
      >
      >>>
      >>>
      >>>>Also, you keep ignoring my remark that the fact that addresses of
      >>>>*Large* objects are fixed is a convenience of the current version
      >>>>of the CLR, nothing stops MS from changing this.
      >>>>
      >>>Which is why the OP is asking for a keyword / MSIL flag that will
      >>>let the runtime know that the object is intended to be fixed for as
      >>>long as it lives. It would be an implementation detail whether the
      >>>memory is allocated from the LOH, OLE task allocator, etc, etc.
      >>>Also I don't think that sacrificing GC for such objects would
      >>>necessaril y be a big loss, they either will live to the end of the
      >>>process anyway, or they can be explicitly freed.
      >>>>
      >>>
      >>But , this is what "fixed" is meant for, sure, it's scope is limited
      >>by it's containing function scope, but you can perfectly pin an
      >>object across several unmanaged function calls.
      >>
      >But it needs an "unsafe" block, for no apparent reason.
      >
      "unsafe" blocks are needed when using pointers!
      This produces non-verifiable code, so no surprises here, you are
      warned.....
      GCHandle.Alloc and Marshal.UnsafeA ddrOfPinnedArra yElement are verifiable and
      need no unsafe block.
      >
      Willy.

      Comment

      Working...