解决方案:JVM(2)垃圾收集器
优采云 发布时间: 2022-12-01 13:33解决方案:JVM(2)垃圾收集器
1.对象存活
内存回收和分配主要集中在堆内存和方法区内存(程序计数器占用空间小,虚拟机栈和本地方法栈与线程有相同的生命周期)。
1.1、引用计数算法
向对象添加引用计数。只要有对它的引用,计数器就会加一;当引用无效时,计数器减一;
优点:实现简单,判断效率高;
缺点:难以解决对象间相互循环引用的问题,不能回收;
1.2. 可达性分析算法
该算法的基本思想是以一系列称为“GC Roots”的对象为起点,从这些节点开始向下搜索,形成一条引用链。当一个对象没有任何到 GC Roots 的引用链时,它就被判定为死亡。Java语言中可以作为GC Roots的对象包括:
1.3、对象引用类型
java中有四种类型的引用:
1.4. 物标回收流程
即使是在可达性分析算法中不可达的对象也不是“必死”的。此时,他们暂时处于“试用期”阶段。真正要告死一个对象,至少要经过两个标记过程:如果对象经过reachability分析后,发现没有引用链连接到GC Roots,就会第一次被标记并筛选一次。筛选条件是是否需要对该对象执行finalize()方法。当对象没有覆盖finalize()方法,或者finalize()方法已经被虚拟机调用过时,虚拟机将这两种情况都视为“不需要执行”。
如果确定这个对象需要执行finalize()方法,那么这个对象就会被放入一个叫做F-Queue的队列中,之后由虚拟机自动创建一个低优先级的Finalizer线程来执行它。这里所谓的“执行”是指虚拟机触发这个方法,但并不承诺等待它结束。这样做的原因是,如果一个对象在finalizer方法中执行缓慢,或者出现死循环(更极端的情况),很可能会导致F-Queue中的其他对象永远等待,甚至导致整个内存回收系统坠毁。finalize()方法是对象逃脱死亡命运的最后机会。稍后,GC 会标记 F-Queue 中的对象,进行第二次小范围的标记。
1.5. 回收方法区
永久代垃圾回收主要回收两部分;过时的常量和无用的类。回收过时的常量与回收 Java 堆中的对象非常相似。以常量池中字面量的回收为例,如果一个字符串“abe”进入了常量池,但是当前系统中没有任何名为“abc”的字符串对象,也就是说没有字符串对象常量池中的“abc”常量被引用,没有其他引用这个字面量。如果此时发生内存回收,必要时系统会将“abc”常量从常量池中清除。常量池中其他类(接口)、方法、字段的符号引用也类似。
判断一个常量是否为“废弃的常量”比较简单,但是判断一个类是否为“无用类”的条件就比较苛刻。
一个类需要同时满足以下三个条件才能被认为是“无用类”:
2. 垃圾采集
算法 2.1. 标记清除算法:
最基本的采集
算法是“标记-清除”(Mark-Sweep)算法。该算法分为两个阶段:“标记”和“清除”。首先标记所有需要回收的对象,标记的都是Object。
标记清除.png
主要有两个缺点:
2.2. 复制算法
复制算法根据容量将可用内存分成两个大小相等的块,并且一次只使用其中一个。当这块内存用完后,将存活的对象复制到另一块中,然后一次性清理掉已使用的内存空间。这样每次都回收了整个半个区域,分配内存时就不用考虑内存碎片等复杂情况。只需要移动堆顶指针,按顺序分配内存即可,实现简单,运行高效。只是这个算法的代价是将内存减少到原来的一半大小,有点太高了。
2.3. 标记排序算法
复制采集
算法在对象存活率高的时候会执行更多的复制操作,效率会变低。更重要的是,如果不想浪费50%的空间,就需要有额外的空间分配保证来应对已用内存中所有对象都是100%存活的极端情况,所以不能直接在老年代算法中选择这个选项。根据老年代的特点,提出了另一种“标记紧凑”(Mark-Compact)算法。标记过程还是和“mark-clear”算法一样,只是后面的步骤不是直接清理可回收对象,而是让所有存活的对象移动到一端,然后直接清理内存之外的内存结束边界。
标记完成.png
2.4. 世代相传的想法
分代采集
算法根据对象的生命周期将内存分成若干块。一般Java堆分为新生代和老年代,这样可以根据各个年代的特点采用最合适的采集
算法。
在新生代中,每次垃圾回收时发现大量对象死亡,只回收少数存活的对象,所以采用复制算法,只需要付出a的复制成本就可以完成回收少数幸存的对象。在老年代,由于对象存活率高,没有多余的空间分配给它,所以需要使用“mark-clean”或“mark-clean”算法进行回收。
3. HotSpot算法的实现 3.1.枚举根节点
GC Root 查找引用链的缺点:
在 HotsPoL 的实现中,使用了一组称为 OopMap 的数据结构来存储对象引用。当类加载完成后,HotSpot会计算出对象偏移处数据的类型,并在JIT编译过程中,在具体位置也会记录栈和寄存器中哪些位置是引用。这样GC在扫描的时候就可以直接知道参考信息。
3.2. 安全要点
Hotspot可以通过OopMap快速完成GC Root的遍历,但是有很多东西会导致OopMap的内容发生变化。如果每条指令都生成对应的OopMap,需要额外占用大量空间,GC的空间成本会很高。变得很高大。
实际上,Hotspot 只记录“特定位置”的 OopMap 信息。这些位置被称为安全点(safepoino,即程序执行不会在所有地方都停下来开始GC,只有到了安全点才能暂停。一般选择方法调用、循环跳转、异常跳转等指令被用作安全点。
safepoint需要考虑的问题是GC发生时,如何在safepoint停止所有线程。
有两种选择:
抢占式中断:抢占式中断不需要线程的执行代码主动配合。当GC发生时,所有线程首先被中断。如果发现线程中断的地方不在安全点,就恢复线程,让它跑到安全点。点击中断。很少有虚拟机实现使用抢占式中断来挂起线程以响应 GC 事件。
主动中断:当GC需要中断线程时,并不直接对线程进行操作,而是简单地设置一个标志,每个线程在执行时主动轮询该标志,发现中断标志是时,中断并挂起自己真的。轮询标志与安全点重合的地方,加上创建对象需要分配内存的地方。
执行 JNI 调用的线程)“运行”到最近的安全点,然后停止。这里有两种选择:抢占式中断(Preemptivc suspension)和主动中断(volunta port suspension)。所有线程全部中断。如果发现线程中断的地方不在安全点,就会恢复线程,让它“跑”到安全点。很少有虚拟机实现使用抢占式中断来挂起线程以响应 GC 事件。主动中断的思想是当GC需要中断线程时,并不直接对线程进行操作,而是简单地设置一个标志,每个线程在执行时主动轮询这个标志,发现时中断并挂起自己中断标志为真。上升。轮询标志与安全点重合的地方,加上创建对象需要分配内存的地方。下面代码清单3中的测试命令是Hotspot生成的轮询命令。当线程需要挂起时,虚拟机就会挂起。, 1 60 100内存页被设置为不可读,当线程执行测试指令时,会产生自陷异常信号,线程会被挂起在预先注册的异常处理器中等待,这样的汇编指令将完成安全点轮询并触发线程中断。
safepoints的选择既不能太小导致GC等待时间太长,也不能太频繁导致运行时负载过大。因此,安全点的选择基本上是以“程序是否具有允许程序长时间执行的特性”为标准——因为每条指令的执行时间很短,程序不太可能被因为指令流的长度太长而执行。“长执行”最明显的特征是指令序列的多路复用,比如方法调用、循环跳转、异常跳转等,所以带有这些功能的指令会产生安全点。
3.3. 安全区
使用safepoint貌似完美解决了如何进入Gc的问题,但实际情况不一定。安全点机制保证了程序在执行的时候,会在不太长的时间内遇到一个可以进入GC的安全点。但是,当程序没有运行的时候,也就是没有分配CPU时间的时候,一个典型的例子就是线程处于休眠状态或者Blocked状态。此时线程无法响应JVM的中断请求,跑到安全的地方中断挂起。JVM 也显然不太可能等待线程重新分配 CPU 时间。对于这种情况,就需要一个安全区域(safe Region)来解决。安全区是指在一段代码内,引用关系不会发生变化。
当线程执行到SafeRegion中的代码时,首先标志自己进入了Safe Region状态。在这段时间里,当JVM要发起GC时,它并不关心标记自己为安全Region状态的线程。当一个线程即将离开安全区域时,它会检查系统是否完成了根节点的枚举(或整个GC过程)。如果完成了,线程会继续执行,否则必须等待,直到收到safe to leave signal在safe Region。
4. 与垃圾回收相关的概念 4.1。垃圾采集
性能指标 4.2.分代采集
模型
世代采集
(Generation 采集
)是指在内存空间划分不同的区域,每个区域存储不同年龄的对象,每个区域可以根据自身特点灵活采用自己的采集
策略。
根据存储对象的年龄,分代可以分为3种类型:
根据垃圾回收在不同代中的作用,垃圾回收类型分为两种:
分配空间的时候,先在new era的伊甸区分配。当Eden区内存耗尽时,会触发Minor GC;在复制链接中,存活对象会被复制到一个Survivor区。如果 Survivor 区已满,将允许对象的一个子集被提升到老年代。当提升时发现老年代没有多余空间时,会通过Full GC回收整个堆空间(CMS除外)。
JVM通过两个参数来判断一个对象是否可以晋升到老年代:
4.3. 快速配送
通常,系统具有可用于分配对象的最大且最连续的内存块。在这种情况下,如果使用指针碰撞算法来分配对象内存空间,效率是相当可观的。这个算法的思路是:记录下一个分配对象的位置,当有新的对象要分配时,如果检查剩余空间容纳该对象,那么只需要一次移动指针的操作完成内存分配。
对于多线程应用,分配操作需要保证线程安全。如果使用全局锁来保证线程安全的内存分配,就会成为性能瓶颈。所以Hotspot采用了thread-local allocation cache技术(即Thread-Local Allocation Buffers,简称TLABs)。每个线程都会有自己的TLAB,就是Eden区的一个小空间。因为每个 TLAB 只对一个线程可见,分配操作可以使用 bump-the-pointer 技术快速完成,无需使用任何锁定机制:只有当一个线程填满一个 TLAB 并需要获取一个新的时,同步是必须的. 在虚拟机开启了UseTLAB选项的前提下,在分配新的对象空间时,会先尝试在TLAB空间中分配对象空间。如果空间分配请求失败,
4.4. 堆栈分配和逃逸分析
栈上分配的基本思想是这样的:分析局部变量的范围仅限于方法内部。然后 JVM 直接在栈帧中分配对象空间,避免在堆中分配。这个分析过程称为逃逸分析,在栈帧中分配对象的方法称为栈上分配。这样做的目的是减少新生代的集合数量,间接提高JVM的性能。
4.5. 垃圾采集
器的设计演变 5. 垃圾采集
器介绍 5.1.串行采集
器
串行采集
器是一个单线程采集
器。它的“单线程”意义不仅仅意味着它只会使用一个CPU或一个采集
线程来完成垃圾采集
,更重要的是,当它采集
垃圾时,必须挂起所有其他工作线程,直到它完成采集
。
与其他采集
器相比,它也有优势:简单高效(相对于其他采集
器的单线程),对于仅限于单CPU的环境,Serial采集
器没有线程交互开销,自然而然会专注于垃圾采集
Get单线程采集
效率最高。在用户的桌面应用场景中,分配给虚拟机管理的内存一般都不会很大,采集
新生代的几十兆甚至一两百兆(仅新生代使用的内存,桌面应用基本上做不管它有多大),停顿时间可以控制在几十毫秒以内,最多一百毫秒。只要不是经常发生,这种停顿是可以接受的。所以,
串口.png
5.2、ParNew采集
器
ParNew 采集
器实际上是 Serial 采集
器的多线程版本。除了使用多线程进行垃圾回收外,其行为还包括Serial采集
器可用的所有控制参数(例如:-XX:SurvivorRatio、-XX:PretenureSizeThreshold、-XX:HandlePromotionFailure等)、采集
算法、Stop The World、对象分配规则、回收策略等与Serial采集
器完全相同。事实上,这两个采集
器共享相当多的代码。
ParNew 采集
器除了多线程采集
器之外,与Serial 采集
器相比并没有太多创新之处,但它是许多运行在Server 模式下的虚拟机的首选新生代采集
器。其中之一是与性能无关但重要的原因是,除了Serial采集
器之外,目前只有它与CMS采集
器一起使用。
ParNew 采集
器在单 CPU 环境下永远不会比 Serial 采集
器有更好的效果。即使由于线程交互的开销,采集
器在超线程技术实现的双 CPU 环境中也不能 100% 有效。保证覆盖串行采集
器。当然,随着可以使用的CPU数量的增加,对于GC时有效利用系统资源还是很有好处的。
ParNew.png
5.3、Parallel Scavenge采集
器
Parallel scavenge collector是新一代的使用复制算法的采集
器,是一种并行的多线程采集
器。Parallel scavenge 采集
器的特点是它的侧重点不同于其他采集
器。Parallel scavenge collector的目标是达到一个可控的吞吐量(Throughput)。所谓吞吐量就是运行用户代码的CPU时间占总CPU时间的比值,即吞吐量=运行用户代码时间/(运行用户代码时间+垃圾回收时间),虚拟机已经运行了一共100分钟,其中垃圾回收用了1分钟,也就是99%的吞吐量。
暂停时间越短,越适合需要与用户交互的程序。良好的响应速度可以提升用户体验,而高吞吐量可以高效利用CPU时间,尽快完成程序的计算任务。主要适用于后台计算,而不是需要过多交互的Tasks。Parallel Scavenge采集
器提供了两个参数来精确控制吞吐量,分别是控制最大垃圾采集
暂停时间的-XX:MaxGCPauseMillis参数和直接设置吞吐量大小的-XX:GCTimeRatio参数。
MaxGCPauseMillis参数允许的值为大于0的毫秒数,采集
器会尽量保证内存回收花费的时间不超过设定值。但是不要以为这个参数的值设置的小一点,系统的垃圾回收速度就会快一些。GC暂停时间的缩短是以吞吐量和新生代空间为代价的;更小,采集
新生代的300MB肯定比采集
500MB快,这直接导致垃圾采集
更频繁。以前是10秒采集一次,停顿100毫秒,现在是5秒采集一次,停顿70毫秒。毫秒,停顿时间确实下降了,但是吞吐量也下降了。
GCTimeRatio参数的值应该是一个大于0小于100的整数,即垃圾回收时间占总时间的比例,相当于吞吐量的倒数。如果这个参数设置为19,最大允许的GC时间会占总时间的5%(即 1 / ( 1 + 19 ) ),默认为99,也就是允许最多占1%(即1 / ( 1 + 99 ) ) 垃圾采集
时间。
由于与吞吐量的密切关系,Parallel scavenge 采集
器也常被称为“吞吐量优先”的采集
器。除了以上两个参数,Parallel scavenge collector还有一个参数-xx:+UseAdaptiveSizePolicy值得关注。这是一个开关参数。开启该参数后,无需手动指定新生代的大小(-Xmn)、Eden占幸存者区域的比例(-xx:SurvivorRatio)、老年代对象的年龄( -xx : PretenureSizeThreshold )等详细参数,虚拟机根据当前系统运行状态采集
性能监控信息,动态调整这些参数以提供最合适的停顿时间或最大吞吐量。
5.4、Serial老采集器
Serial old是老版本的Serial采集
器,也是单线程采集
器,使用“标记-排序”算法。这个采集
器的主要意义也是在客户端模式下用于虚拟机。如果是server模式,主要有两个用途:一是配合JDK 1.5及更早版本中的Parallel scavenge collector使用。,另一个用途是作为CMS采集
器的备份计划,在并发采集
出现Concurrcnt Mode Failure时使用。这两点将在后面的内容中详细说明。
SerialOld.png
5.5、并行旧采集
器
Parallel old 是 Parallel 清道夫采集
器的老一代版本,它使用多线程和“标记与排序”算法。如果新生代选择Parallel Scavenge采集
器,那么老年代就只能选择Serial Old (Ps Markswccp)采集
器了。由于老年代Serial Old采集
器对服务器应用程序性能的“拖累”,使用Parallel Scavcnge采集
服务器可能无法最大化整体应用程序的吞吐量,因为单线程老年代采集
器不能充分利用服务器的多CPU处理能力。在老年代很大、硬件比较先进的环境下,这种组合的吞吐量可能甚至没有那么“强大” 作为 ParNew 和 CMS 的组合。直到Parallel Old采集
器的出现,“吞吐量优先”的采集
器终于有了更名副其实的应用组合。在注重吞吐量和对CPU资源敏感的场合,可以优先考虑Parallcl Scavcnge plus Parallel Old collector。
" />
ParallelOld.png
5.6、CMS采集
器
CMS(Concurrent Mark sweep)采集
器是一种旨在获得最短恢复停顿时间的采集
器。目前,很大一部分Java应用都集中在互联网网站或B/S系统的服务器端。这类应用特别注重服务的响应速度,希望系统停顿时间最短,给用户带来更好的体验。CMS采集
器非常适合这类应用的需求。
CMS采集
器基于“mark-clear”算法实现,整个过程分为四步:
由于整个过程中耗时最长的采集
器线程可以和用户线程一起工作,所以CMS采集
器的内存回收过程是和用户线程并发执行的。
cms.png
CMS的缺点是:
5.7、G1采集
器
G1采集
器具有以下特点:
G1中的堆内存布局:
G1将整个Java堆划分为多个大小相等的独立区域(Region)。虽然仍然保留了新生代和老年代的概念,但新生代和老年代不再是物理隔离的。它们都是区域的一部分(不需要连续)。
G1跟踪每个Region的垃圾堆积值(回收获得的空间大小和回收所需时间的经验值),并在后台维护一个优先级列表。每次根据允许的采集时间,优先采集值最大的Region。(这就是 Garbage-First 名称的来源)。这种使用Region划分内存空间和优先区域回收的方式,保证了G1采集
器在有限的时间内获得尽可能高的采集
效率。
在Gl采集
器中,对于Region之间的对象引用以及其他采集
器中新生代和老年代之间的对象引用,虚拟机使用Remembered Set来避免全堆扫描。G1 中的每个 Region 都有对应的 Remembered Set。当虚拟机发现程序正在写入引用类型的数据时,会生成一个Write Barrier暂时中断写入操作,并检查Reference所引用的对象是否在不同的Region中。其中(在generation的例子中,就是检查old generation中的对象是否引用了new generation中的对象),如果是,则通过Card Table。将相关引用信息记录到引用对象所属Region的Remembered Set中。在执行内存恢复时,
如果不算维护Remembered set的操作,GI采集
器的操作大致可以分为以下几步:
最后,在筛选回收阶段,首先,根据Sun公开的信息,这个阶段其实可以和用户程序并发执行,但是因为只回收了一部分Region,所以时间是可控的user,而暂停用户线程会大大提高采集效率。
5.8. 垃圾采集
器参数汇总参数说明
-XX:+UseSerialGC
在年轻代和老年代使用串行采集
器
-XX:幸存者比率
设置eden区大小与survivor区大小的比例
-XX:PretenureSizeThreshold
设置大对象直接进入老年代的阈值。当对象的大小超过这个值时,会直接分配到老年代。
-XX:MaxTenuringThreshold
设置对象进入老年代的最大年龄。每次Minor GC后,对象的年龄加1,任何超过这个年龄的对象都必须进入老年代
参数说明
-XX:+UseParNewGC
在年轻代使用并行采集
器
-XX:+UseParallelOldGC
老年代使用并行采集
器
-XX:并行GC线程
设置用于垃圾回收的线程数。通常可以等于CPU个数,但在CPU个数较多的情况下,设置一个比较小的值比较合理。
-XX:MaxGCPauseMillis
设置最大垃圾采集
暂停时间。它的值是一个大于0的整数。采集
器在工作时,会调整Java堆大小或其他参数,尽可能将停顿时间控制在MaxGCPauseMillis以内。
-XX:GCTimeRatio
设置吞吐量大小。它是一个从 0 到 100 的整数。假设 GCTimeRatio 的值为 n,系统将花费不超过 1/(1+n) 的时间进行垃圾回收。
-XX:+UseAdaptiveSizePolicy
开启自适应 GC 策略。在这种模式下,新生代的大小、eden 和 survivor 的比例、晋升到老年代的对象的年龄等参数都会自动调整,以在堆大小、吞吐量和停顿时间之间达到平衡。
参数说明
-XX:+UseConcMarkSweepGC
新生代使用并行采集
器,老年代使用CMS+串行采集
器
-XX:并行CMS线程
设置 CMS 的线程数
-XX:CMSInitiatingOccupancyFraction
设置CMS采集
器在老年代空间使用后触发,默认68%
-XX:+UseCMSCompactAtFull采集
设置CMS采集
器完成垃圾回收后是否进行内存整理
-XX:CMSFullGCsBeforeCompaction
设置好CMS垃圾回收次数后,进行一次内存压缩
-XX:+CMSClassUnloadingEnabled
允许回收类元数据区域
-XX:CMSInitiatingPermOccupancyFraction
当永久区域占用达到这个百分比时,开始CMS回收(前提是-XX:+CMSClassUnloadingEnabled被激活)
-XX:UseCMSInitiatingOccupancyOnlyn
表示只有达到阈值才会执行CMS回收
-XX:+CMSIncrementalMode
使用增量模式更适合单CPU。增量模式在 JDK8 中被标记为过时,并将在 JDK 9 中完全删除。
参数说明
-XX:+使用G1GC
使用 G1 采集
器
-XX:MaxGCPauseMillis
设置最大垃圾回收暂停时间
-XX:GCPauseIntervalMillis
设置暂停间隔
参数说明
-XX:+使用TLAB
启用 TLAB 分配
-XX:+PrintTLAB
打印TLAB相关分配信息
-XX:TLABSize
设置 TLAB 大小
自动调整 TLAB 大小
参数说明
-XX:+DisableExplicitGC
禁用显式 GC
-XX:+ExplicitGCInvokesConcurrent
使用并发处理显式 GC
5.9 垃圾采集
器比较
比较.png
" />
采集
器算法并发并行 STW 适用生成
连续剧
复制
不
不
是的
新一代
标准杆新
复制
是的
是的
不
新一代
并行清除
复制
是的
是的
不
新一代
序列号旧
标记组织
不
不
是的
老一辈
并行老
标记组织
是的
是的
不
老一辈
内容管理系统
清除标记
是的
是的
是的
老一辈
G1
世代采集
是的
是的
不
旧时代,新一代
Collector适用场景优缺点
连续剧
单CPU,客户端模式
简单高效,无线程切换开销,专注于GC
STW
标准杆新
多CPU,服务器模式
并行并发 GC
STW
并行清除
吞吐量优先级,客户端或服务器模式
吞吐量优先级,设置吞吐量以适应不同的场景
序列号旧
单CPU,客户端模式
简单高效,无线程切换开销,专注于GC
STW
并行老
吞吐量优先级,客户端或服务器模式
吞吐量优先级,设置吞吐量以适应不同的场景
内容管理系统
互联网; B/S系统服务
并发采集
,低暂停
对CPU资源敏感,无法处理浮动垃圾,内存碎片
G1
对于服务器端应用程序
并发并行、分代采集
、可测停顿、空间整合
6. 内存分配与回收策略 6.1. 对象首先在伊甸园分配
大多数时候对象是在伊甸园中分配的。当Eden中没有足够的空间分配时,JVM会发起一次Minor GC。,
次要垃圾回收(Minor GC):指发生在新生代的垃圾回收。由于大多数JAVA对象都有注册和死亡的特点,所以Minor GC非常频繁,回收速度普遍较快。
老年代GC(Major GC/Full GC):指发生在老年代的GC。Major GC 的发生,通常伴随着至少一次 Minor GC。Major GC 一般比 Minor GC 快 10 倍。
6.2. 大对象直接进入老年代
所谓大对象是指需要大量连续内存空间的java对象,比如很长的字符串、数组等。大对象对于虚拟机的内存分配来说是个坏消息(抱怨Java虚拟机,比遇到大对象更坏的消息是遇到一群“生死存亡”的“短命大对象”,写programs should be avoided),频繁的大对象很可能导致垃圾回收在内存中还有大量空间获取足够的连续空间来“放置”它们时被提前触发。虚拟机提供了一个-XX:PretenureSizeThreshold参数,让大于这个设置值的对象直接在老年代分配。这样做的目的是为了避免在Eden区和两个Survivor区之间进行大量的内存复制(回收新生代使用复制算法采集
内存)。PretenureSizeThreshold 参数仅对 Serial 和 ParNew 采集
器有效。
6.3. 长寿对象会进入老年代
虚拟机为每个对象定义一个对象年龄(Age)计数器。如果对象出生在Eden,在第一个Minor GG后存活下来,并且可以被Survivor容纳,则将其移动到Survivor空间,并设置对象的age为1。每有一个对象“存活”一个Survivor区的Minor GC,其年龄会增加1年。当它的年龄增长到一定程度(默认是15岁),就会被提升到老年代。将对象提升到 Old Age 的年龄阈值可以通过参数 -xx : MaxTenuringThreshold 设置。
6.4. 动态对象的年龄确定
为了更好的适应不同程序的内存状态,虚拟机并不总是要求对象的年龄必须达到MaxTenuringThreshold才能提升到老年代。如果survivor空间中所有同age的对象size之和大于Survivor空间的一半,则age大于等于这个age的对象可以直接进入老年代,无需等待MaxTenuringThreshold中要求的age .
6.5. 空间分配保证
在Minor GC发生之前,虚拟机首先检查老年代中的最大可用连续空间是否大于新生代中所有对象的总空间。如果这个条件为真,那么Minor GC可以保证它是安全的。如果不是,则虚拟机检查 HandlePromotionFailure 设置值是否允许保证失败。如果允许,它会继续检查老年代的最大可用连续空间是否大于提升到老年代的对象的平均大小。如果大于,它会尝试进行一次Minor GC,虽然这个Minor GC有风险:如果小于,或者HandlePromotionFailure设置不允许风险,那么此时也应该进行一次Full GC。
解决方案:Meta宣布将通过保护Facebook的标识符来阻止采集行为
作为我们正在进行的解决数据滥用问题系列的一部分,Meta 最近分享了有关我们的外部数据滥用 (EDM) 团队如何保护人们免受克隆网站侵害的最新消息。今天,官方博客详细介绍了如何阻止在 Facebook 上采集
Facebook 标识符 (FBID)。
大多数公司在其网站的 URL 中使用唯一标识符。标识符是一种唯一引用人或内容的方式,例如帖子、图像和视频。在 Facebook 内部,这些标识符被称为 FBID,它们用于为人们加载内容。
" />
采集
是指从网站或应用程序自动采集
数据,可以是授权的也可以是未授权的。未经授权的采集
通常涉及猜测标识符,或使用购买的标识符来采集
有关人员的数据。在某些情况下,收割者采集
标识符并碰撞和交叉过滤电话号码或其他公开可用的数据,以创建可重复使用的数据集,这些数据集有时会被出售以牟利。
图为 URL 中带有 PFBID 的 Facebook 帖子示例
" />
考虑到这一点,Meta 创建了假名化的 Facebook 标识符 (PFBID),它将时间戳和 FBID 结合起来生成一个唯一的时间旋转标识符。随着访问原创
标识符的能力被逐步淘汰,这有助于防止未经授权的数据抓取,使攻击者更难猜测、连接和重新访问数据。
这些标识符并非旨在防止浏览器工具从 URL 中删除跟踪组件,该过程是为了更好地保护人们的隐私免受某些类型的枚举和延迟攻击,同时保留持久链接的能力。
用户可以在 Facebook 的“隐私问题”页面上阅读有关隐私倡议的更多更新和见解: