我看着视频 谷歌IO2008-安装虚拟机器内部 要了解如何安装VM工作以及为什么那些人具有优选的安装VM过JVM序。我发现,使用单独的存储器对垃圾信息的对象,而不是JVM我们在那里有标记的位(位诉是否对象是能够为garbagfe收集或不)一起对象。

谁能告诉我在详细说明有哪些优点和缺点的具有单独的存储器标记的位并不具有单独的存储器标记的位?

我是无法得到这种差异通过观看视频。

有帮助吗?

解决方案

一些优点的一个单独的位图:

  • 从更密。一个典型的GC的需要可能有八位的GC元数据,但是由于对准一个目的标题可能会轮这种存储器升到32位。
  • 一些行动,尤其是周围扫地,成为更快。这部分是因为更密集(见上文)bitmap意味着减少存储器交通和更好地使用缓存,而且还因为某些操作(例如零所有标记的位)可以量化时,这种格式。(其他部分的GC需要设计利用这种能力。)
  • 如果你 fork() 在类Unix系统中,一个独立的bitmark可以更好地使用复制上写的:网页包含对象可能仍然是共用的。

一些优点,在目标位:

  • 取决于所使用的方案的关联对象位图,获取标记点为对象,反之亦然可能相当复杂和/或缓慢的。一个对象头,另一方面,是微不足道的访问。
  • 更容易存管理:没有必要建立一个单独的分配的正确的尺寸和保持同步。
  • 许多快速的方案对于找到位图的对象,反之亦然是相当限制性的在其他方面。例如,如果创建了一个位于每一页和存储位的指针在开始新的一页,你有一个问题储存的对象超过一页。

其他提示

单独的标记位通过具有阵列的比特数组,其中每个位表示可以启动对象的堆中的地址。例如,假设堆为65536字节,并且所有对象都在16个字节边界对齐,然后堆中有4096个地址,可以是对象的开始。这意味着数组需要包含4096位,可以有效地存储为512字节或64 64位尺寸的无符号整数。

对象标记位通过将每个对象的每个标题的一位设置为1,如果对象标记为1,否则为0。请注意,这要求每个对象都有一个专用标题区域。运行时,如JVM和.NET都将标题添加到对象,因此您基本上可以免费获得标记位的空间。

但它不适用于保守收集器,这些收集器没有完全控制他们在运行的环境,例如 boehm gc 。它们可以将整数定义为指针,因此对于它们修改突变者中的任何内容数据堆都存在风险。

标记和扫描垃圾收集分为两个阶段:标记和扫描。使用对象标记位的标记是直接的(伪代码):

if not obj.is_marked():
    obj.mark()
    mark_stack.append(obj)
.

使用单独的数组来存储标记位,我们必须将对象地址和大小转换为位阵列中的索引,并将相应的位设置为1:

obj_bits = obj.size_in_bytes() / 16
bit_idx = (obj - heap.start_address()) / 16
if not bitarr.bit_set(bit_idx):
    bitarr.set_range(bit_idx, obj_bits)
    mark_stack.append(obj)
.

所以在我们的示例中,如果对象长度为128个字节,则在位阵列中将设置8位。显然,使用对象标记位更简单。

但单独的标记位在扫描时会产生一些动力。扫描涉及通过整个堆扫描并找到未标记的持续内存区域,因此可以再生。使用对象标记位,它将大致如此:

iter = heap.start_address()
while iter < heap.end_address():
    # Scan til the next unmarked object
    while iter.is_marked():
        iter.unmark()
        iter += iter.size()
        if iter == heap.end_address():
            return
    # At an unmarked block
    start = iter
    # Scan til the next marked object
    while iter < heap.end_address() and not iter.is_marked():
        iter += iter.size()
    size = iter - start
    # Reclaim the block
    heap.reclaim(start, size)
.

注意迭代如何从对象跳转到iter += iter.size()行中的对象。这意味着扫描阶段运行时间与Live和垃圾对象的总数成比例。

使用单独的标记位,除了将大量的垃圾对象流出,您将执行大致相同的循环,而不会在它们中的每一个上的“停止”。

再次考虑65536堆。假设它包含所有垃圾的4096个对象。迭代标记位阵列中的64 64位整数并看到它们都是0显然非常快。因此,扫描阶段可能与单独的标记比特更快。

但还有另一个皱纹!在任何标记和扫描收集器中,运行时间由标记阶段主导,而不是通常非常快速的扫描阶段。所以判决仍然出来了。一些更喜欢单独的标记比特,其他更喜欢对象中的标记位。据我所知,没有人能够展示哪种方法优于另一个方法。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top