Java内存区域和垃圾收集器
我昨天读到了关于垃圾收集的文章,但我不理解其中的一些概念。我读过,对于次要收集,通常使用复制技术将可到达的对象移动到幸存者空间,而对于主要收集,通常使用标记和扫描 我不明白的第一件事是垃圾收集器从gc根开始,沿着图移动以检测活动实例,但它如何知道哪个对象是年轻的,哪个对象是旧的?它如何知道对象所在的内存区域 第二件事是,如果我们只进行小的收集,gc如何知道年轻一代中的对象不是由老一代中的对象引用的,还是由方法区域中的静态引用引用的 最后一件事是,在标记和扫掠之后,有时会进行压实。gc如何知道对移动对象的哪些引用必须更新?如果我们有一个程序,有数千个线程,使用巨大的帧堆栈和千兆字节的堆?它是否有一些内部结构,以地图或其他形式包含这些信息 谢谢Java内存区域和垃圾收集器,java,garbage-collection,Java,Garbage Collection,我昨天读到了关于垃圾收集的文章,但我不理解其中的一些概念。我读过,对于次要收集,通常使用复制技术将可到达的对象移动到幸存者空间,而对于主要收集,通常使用标记和扫描 我不明白的第一件事是垃圾收集器从gc根开始,沿着图移动以检测活动实例,但它如何知道哪个对象是年轻的,哪个对象是旧的?它如何知道对象所在的内存区域 第二件事是,如果我们只进行小的收集,gc如何知道年轻一代中的对象不是由老一代中的对象引用的,还是由方法区域中的静态引用引用的 最后一件事是,在标记和扫掠之后,有时会进行压实。gc如何知道对移
答案取决于GC算法,因此您将在答案中发现一些变化 GC如何知道哪个对象是年轻的,哪个对象是旧的?它如何知道对象所在的内存区域 对象的内存地址将回答这个问题,因为每个区域的位置趋于固定。调整大小是可能的,但只有当JVM暂停所有工作线程时才会发生。还请记住,G1收集器没有代,因此答案会因所使用的算法而异 gc如何知道年轻一代中的对象是不是被旧一代中的对象引用,还是被方法区域中的静态引用引用 一些GC算法将对堆中的所有对象执行完全扫描。其他人则依赖于这样的观察:从老代到年轻代的ref数量相对较低,因此JVM会跟踪它们,并将它们用作根来进行标记。其机制通常是一个记分卡系统,这就是为什么一些GC算法具有非常大的祖先空间,会减慢年轻空间的GC的速度。因为每一个物体的每一张记分卡都必须被检查,看它是否有一个指向年轻一代的指针 最后一件事是,在标记和扫掠之后,有时会进行压实。gc如何知道对移动对象的哪些引用必须更新 同样,答案也会有所不同,因为JVM可以改变这些细节。有些算法使用双间接寻址,因此指针很容易定位和更新。这涉及到为每个对象存储一个大索引。然而,当GC没有运行时,这会减慢用户代码的速度,因为运行的代码必须不断查找对象的实际位置,所以一些GC算法确实会跟踪引用
Azul使用了一种非常聪明的机制,使内存页无效,并存储在陷阱处理程序代码中访问的重定向映射。因此,它只需要存储已移动对象的地址。而其他GC算法在扫描活动对象时跟踪信息。毕竟,我们不需要死堆的信息。YoungGen/OldGen和PermGen是Java堆所在的三个区域。JVM非常熟悉每种语言的边界
谢谢@Geek!还有一件事,GC是如何执行小收集的?它是否也适用于采摘GC根?我知道在小集合中,你们不想触碰老一代中的那个些,所以GC如何决定应该在小集合中处理哪些GC根呢?谢谢Chris!我可以请你检查一下我在极客答案评论中的问题吗?@alobodzk如果我们选择一个算法,我们可以更具体。所以,让我们来看看CMS,Oracle Hotspot的并发标记和扫描的实现。他们年轻的GC使用通常的根,即线程、本机调用等。对于老一代到年轻一代的部分,它们有一个大的位数组,与老一代中的每个内存地址对齐。每个位表示,可能是指向年轻一代的指针(但可能是误报)。年轻一代扫描了这一点,并从中扎根。这些被称为“卡片表”。一些关于卡片表的详细信息可以在这里阅读:谢谢!你提到