【问题标题】:Objects memory re-location?对象内存重新定位?
【发布时间】:2012-07-22 09:29:48
【问题描述】:

有没有办法告诉 .net runtime,在内存中重新定位对象?

恕我直言 - 在以下情况下,GC 可以重新定位对象:

  • 从一代传到另一代
  • 正在从 finilization-queue 移动到 f-reachable 队列。
  • else(可能是优化机制?)。

    另外,我认为不可变(字符串)每次都会自动重新创建,因此必须在新位置创建它们。

(只是一个理论问题)

【问题讨论】:

  • 这有什么意义?在 regular c# 中,对象位置是我们无法获得的实现细节......你想做什么
  • 不可变对象不会被“重新创建”,并且不可变性不会影响对象是否会被重定位。
  • @MarcGravell 正在学习我的朋友,正在学习。
  • @Royi 是的,但您不会想要覆盖旧位置;其他参考可能指向它。如果你在原地重写它,你会意外地改变其他引用所指的内容,
  • @RoyiNamir - s 是引用而不是对象。将分配一个新的字符串“2”,而之前由s 指向的旧字符串“1”将保留。

标签: c# .net memory-management .net-4.0 clr


【解决方案1】:

作为一个实现细节,.Net 框架可以在垃圾回收的最后阶段移动内存中的对象。但这并不一定意味着在世代之间移动:在执行第 2 代 GC 时,第 2 代中的对象将被移动,即使它们不会改变世代(因为没有地方可以超越第 2 代)。

finalization queue 和 f-reachable queue 与此无关,它们只包含对对象的引用,而不是对象本身。

我不知道这与不可变对象有什么关系。运行时不会对它们进行任何特殊处理(字符串除外)。

告诉运行时不要重新定位对象(也称为“固定”对象)是一个不寻常的要求,应该有一个很好的理由,因为它会对 GC 的性能产生负面影响。要在不安全代码中临时固定对象,您可以使用the fixed statement。要永久执行此操作或通过安全代码执行此操作,您可以使用GCHandle.Alloc(),指定GCHandleType.Pinned

【讨论】:

  • 你说得对,我错误地认为对象从 1 个队列移动到另一个队列,pointer 被删除。谢谢指正。
  • svick 有 2 个 HEAPS(1 个用于大对象,另一个用于较小对象)这一事实怎么样?是否可以将对象从一个移动到另一个(如果已修改)?
  • 对象的大小永远不会改变,因此移入/移出大型对象堆没有多大意义,也不会发生。 LOH 有用的原因之一是其中的对象没有移动(尽管您不应该依赖它并在大对象上使用固定)。
  • 大对象:(更大的regerence)还是(消耗更多的内存)?
  • 我不明白,引用的大小是恒定的(4 或 8 字节)。大对象几乎只意味着大于 85 000 字节的数组。
【解决方案2】:

Pinned Objects 告诉 gc 不要移动它以创建大量可用空间。它们是使用 Fixed 关键字创建的。

有用的场景

让我们考虑一个场景,我们需要将一个 int 数组传递给某个非托管函数,而非托管函数读取数组的值并进行一些更改。如果数组没有被固定,更改的值将无法写回,因为指向数组的指针已被 GC 移动。

【讨论】:

    【解决方案3】:

    不确定这在问题上下文中是否有用,但在托管场景中,您可以使用 Marshall 类分配内存,将结构移动到分配的内存并获取指针。这个结构不会被 gc 移动。稍后您可以使用之前的指针从分配的内存中检索结构。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-01-18
      • 1970-01-01
      • 2013-03-29
      • 1970-01-01
      • 2011-01-27
      • 1970-01-01
      • 2018-10-25
      • 1970-01-01
      相关资源
      最近更新 更多