前言

做一个有趣的程序员。哈哈哈哈

本次铁村的小蓝猫主要给大家详细分享JVM中垃圾回收机制

学习JVM 肯定是要了解垃圾回收机制的。

分享前,我们先了解下本次分享内容的框架。

一、垃圾回收机制定义

1.1垃圾回收机制是什么

java 程序在运行过程中,会产生大量的内存垃圾。(当一个对象不再被直接或间接的引用。对于程序而言他就是垃圾),为了我们内存不被这些垃圾填满,也为了保证运行性能。java虚拟机在程序运行的过程中不断地进行自动的垃圾回收(GC)。

垃圾回收机制比喻:酒店房间经常有人住,为了保证酒店正常经营。有一个GC(清理工),对没有用房间,进行打扫,以便腾出新的房间。

1.2 分代收集理论

目前虚拟机的垃圾收集器,大多数都遵循了分代收集理论。
分代理论建立假说

1.弱分代假说:绝大多数对象都是朝生夕灭的。
2.强分代假说:熬过越多次垃圾收集过程的对象就越难以消亡。

于是根据对象存活周期将堆内存分为2块,新生代和老年代
弱分代假说设计

新生代 每次有大量对象死亡,每次回收后存活的少量对象,将会逐步晋升年龄(年龄即对象熬过垃圾收集过程的次数)到达一定数量会到老年代中存放。

强分代假说设计
老年代 老不死的对象集中放在这块,虚拟机便可以使用较低的频率来回收这个区域 。

1.2.3 分代图


从这张图中,得出如下结论。

Eden:so:si = 8:1:1
新生代:老年代  =  1:2

默认的,新生代 ( Young ) 与老年代 ( Old ) 的比例的值为 1:2 ( 该值可以通过参数 –XX:NewRatio 来指定 ),即:新生代 ( Young ) = 1/3 的堆空间大小。老年代 ( Old ) = 2/3 的堆空间大小

Minor GC

新生代的垃圾收集动作,Minor GC非常频繁,一般回收速度也比较快。

Full GC

是清理整个堆空间

1.2.4 对象创建于到GC消亡

创建过程

  • 当我们在创建一个对象的时候,JVM通过逃逸分析确定该对象不会被外部访问,如果不会逃逸可以将该对象在栈上分配内存,这样该对象所占用的内存空间就可以随栈帧出栈而销毁,就减轻了垃圾回收的压力。

  • 当对象字节大于JVM参数设置的大对象的字节数,直接进入老年代

  • 小于JVM参数设置的大对象的字节数字,直接进入年轻代的Eden 区s

GC过程

  • 第一次将分配到Eden 区的对象,进行1次Minor GC,清理没用垃圾
  • 第1次没有被处理掉的对象。会移动到Survivor区 中的S0,同时年龄+1
  • 第2次会对Eden 区+Survivor区 也就是整个年轻代,再次进行Minor GC ,清理没用垃圾,将存活对象从S0 移动到S1,同时年龄+1
  • 第3次整个年轻代,再次进行Minor GC ,清理没用垃圾,将存活对象从S1 移动到S0 ,同时年龄+1
  • 以此类推…
  • 当Survivor区 对象达到 -XX:MaxTenurigThreshold参设置的值(默认15),移动到老年代。
  • 当老年代空间满的时候,会触发Full GC (回收整个堆内存)

1.2JVM由什么组成

二、垃圾收集器算法

垃圾回收期是通过以下的3种算法进行垃圾回收。
在了解垃圾回收算法前先了解2个问题。

如何判断一个类是无用的类?

  1. 该类所有的实例都已经被回收,也就是 Java 堆中不存在该类的任何实例。
  2. 加载该类的 ClassLoader 已经被回收。
  3. 该类对应的 java.lang.Class 对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。

采用什么算法判断类可以回收?

根可达性算法

堆空间外的一些结构,比如虚拟机栈、本地方法栈、方法区、字符串常量池等地方对堆空间进行引用的,都可以作为 GC Roots 。

把”GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链,当一个对象到GC Roots没有任何引用链相连时,则证明此对象是不可用的。就意味着该对象己经死亡,可以标记为垃圾对象。

反之够被根对象集合直接或者间接连接的对象才是存活对象

2.1 标记复制

内存对半分,整理前,左边随机存放对象,右边空着。整理后,把存活的对象复制到右边,左边全部清空。

  • 优点:实现简单,运行高效
  • 缺点:将可用内存缩小为了原来的一半,浪费空间

2.2 标记清除

标记存活的对象,统一回收未被标记的对象。也可以反过来标记出所有需要回收的对象,标记完成后统一回收所有被标记的对象。

  • 缺点:
    a. 效率问题:如果需要标记太多,效率不高
    b. 空间问题:标记清除后产生大量不连续的内存碎片

2.3 标记整理

标记过程与标记-清除算法一样,但是后续步骤不是直接对可回收对象回收,而是让所有存活的对象向一端移动,然后直接清理掉边界以外的内存

三、垃圾收集器种类

收集算法是内存回收的方法论,那么垃圾收集器就是内存回收的具体实现。
下图是一张收集器关系图

3.1单线程

3.1.1Serial+SerialOld

历史最悠久的基础单线程垃圾收集器。

3.1.1 使用方式

-XX:+UseSerialGC // 新生代
-XX:+UseSerialOldGC // 老年代
3.1.2 回收过程

一条垃圾收集,线程去完成垃圾收集工作,在进行垃圾收集工作时候必须暂停其他工作线程,STW ,直到收集结束。新生代采用复制算法,老年代采用标记-整理算法

为什么要STW?:如果不STW,不断地有新的局部变量引用新的对象,初始标记就永远做不完了

3.2 多线程

3.2.1 Parallel Scavenge +ParallelOld

Parallel Scavenge 就是Serial的多线程版本, 默认收集线程数跟cpu核数相同,通过-XX:ParallelGCThreads 指定收集线程数,通常不推荐修改。

3.2.1.1 使用方式

-XX:+UseParallelGC // 新生代
-XX:+UseParallelOldGC // 老年代
3.2.1.2 回收过程

多条垃圾收集,线程去完成垃圾收集工作,在进行垃圾收集工作时候必须暂停其他工作线程,STW ,直到收集结束。新生代采用复制算法,老年代采用标记-整理算法。

3.3多线程+并发

3.3.1 ParNew

ParNew 新生代处理器,可以和老年代的SerialOld或者CMS收集器配合使用。
和Parallel 区别就是 可以自由搭配老年代的收集器使用

3.3.1.1 使用方式

-XX:UseParNewGC
3.3.1.2 回收过程

新生代采用复制算法

3.3.2 CMS

CMS 收集器是以获取最短回收停顿时间为目标的收集。

3.3.2.1 使用方式

-XX:+UseConcMarkSweepGC // 老年代
3.3.2.2 回收过程

使用标记-清除算法
整个垃圾回收过程主要是5步:

  • 初始标记:暂停所有的其他线程(STW),用可达性分析算法,并记录下gc roots直接能引用的对象,速度很快。

  • 并发标记:不STW,用户线程可以跟垃圾收集线程一起并发运行,并发标记阶段就是上一步从GC Roots的直接关联对象出发,一直找,遍历整个对象图。因为用户程序继续运行,可能会有导致已经标记过的对象状态发生改变。 可能之前不是垃圾,等并发标记结束时候,就变成垃圾了;也有可能之前是垃圾对象,等并发标记结束之后又被引用了,变成非垃圾。

  • 重新标记:会STW,修复并发标记时候状态改变的对象,停顿时间比初始标记阶段稍长,远远比并发标记阶段时间短,主要是用三色标记算法

  • 并发清理:不需要STW,用户线程和垃圾收集线程并行把标记的对象保留,没有标记的对象清除掉。这个阶段如果有新增对象,会标记为黑色,不做任何处理**(三色标记算法)**

  • 并发重置:重置本次GC过程的标记数据。下次会重新标记。

三色标记算法:处理漏标,多标,假设有3种颜色,默认都是白色,黑色代表分析完了,灰色代表分析过但是还没分析完。如果GC Roots可达性分析完了,还存在白色,白色就要被回收。


CMS的优点:并发收集、低停顿;
CMS的缺点:

  • 对cpu资源敏感,会和服务抢资源
  • 无法处理浮动垃圾
    浮动垃圾:在并发清理阶段,清理没有被标记的对象,可能在某一个区域清理完之后之后又new了一个对象,这个对象又变成垃圾了,这样的对象清理不了,只能等下一次GC清理,这种叫做浮动垃圾。下次GC就会干掉。
  • 使用的回收算法是"标记-清除"算法会产生大量的空间碎片。可以通过设置参数-XX:UserCMSCompactAtFullCollection让jvm在执行完标记清除后再做整理
  • 有一个很大的问题 “concurrent mode failure” 并发模式失败。
    执行过程中的不确定性,会存在上一次垃圾回收还没执行完,然后垃圾回收又被触发。特别是在并发标记和并发清理阶段会出现,一边回收,系统一边运行,也许还没回收完就会触发full GC。此时就会进入stop the word,用serial old垃圾收集器来回收,效率会非常低。

相关场景老年代快满了或者已经满了,此时在做并发标记或者并发清理时,用户线程还在执行,此时如果有一个大对象,老年代放不下了,就会stop the word,用serial old垃圾收集器来回收

3.3.2.3 CMS核心参数

1. -XX:+UseConcMarkSweepGC:启用cms 2.  -XX:ConcGCThreads:并发的GC线程数 3.  -XX:+UseCMSCompactAtFullCollection:FullGC之后做压缩整理(减少碎片),碎片整理也会stop the world,跟剩余存活对象数量有关,剩得越少效率越高,剩得越多效率越低。 4.  -XX:CMSFullGCsBeforeCompaction:多少次FullGC之后压缩一次,默认是0,代表每次FullGC后都会压缩一次。配3代表每3次FullGC压缩一次 (3,4通常一起配)。如果频繁full gc就2,3次一次。如果不频繁就配0 。 5.  -XX:CMSInitiatingOccupancyFraction: 当老年代使用达到该比例时会触发FullGC(默认是92,是百分比)。这个参数为了避免并发模式失败,具体根据机器配置去配,如果是高配可以适当调高,低配适当调低。如果配得太低,比如80,可能会导致老年代有20%永远用不到,浪费了资源。 6.  -XX:+UseCMSInitiatingOccupancyOnly:只使用设定的回收阈值(-XX:CMSInitiatingOccupancyFraction设定的值),如果不指定,JVM仅在第一次使用设定值,后续则会自动调整。 7.  -XX:+CMSScavengeBeforeRemark:在CMS GC前启动一次minor gc,目的在于减少老年代对新生代的引用,降低CMS GC标记阶段时的开销,一般CMS的GC耗时 80%都在标记阶段。如果老年代和新生代有跨代的地方,CMS做标记的时候要标过去,如果在GC之前先MinorGC一次,就不用去新生代标记了,加快并发标记阶段跨代引用很少,配不配意义不大,Full GC会优先做老年代的收集,然后做MinorGC。8.  -XX:+CMSParallellnitialMarkEnabled:表示在初始标记的时候多线程执行,缩短STW。 9.  -XX:+CMSParallelRemarkEnabled:在重新标记的时候多线程执行,缩短STW

3.3.2 G1

一款面向服务器的垃圾收集器,针对配备多颗处理器及大容量内存的机器。以极高概率满足GC停顿时间要求的同时,还具备高吞吐量性能特征。
JDK9默认G1,CMS过时。
G1的Mixed GC模式:面向堆内存任何部分来组成回收集(Collection Set,一般简称CSet)进行回收,衡量标准不再是它属于哪个分代,而是哪块内存中存放的垃圾数量最多,回收收益最大

G1把连续的Java堆划分为多个大小相等的独立区域(Region),将Region作为单次回收的最小单元,即每次收集到的内存空间都是Region大小的整数倍。

每一个Region都可以根据需要扮演新生代的Eden、Survivor区或者老年代。收集器根据扮演不同角色的Region采用不同的处理策略。

JVM目标是不超过2048个Region,实际可以超过该值,但是不推荐。一般Region大小等于堆大小除以2048比如堆大小为4096M,则Region大小为2M,当然也可以用参数"-XX:G1HeapRegionSize"手动指定Region大小,取值范围为1MB~32MB,且应为2的N次幂,但是推荐默认的计算方式。

G1仍然保留新生代和老年代的概念,但新生代和老年代不再是固定的了,它们都是一系列区域(不需要连续)的Region集合。一个Region可能之前是新生代,如果Region进行了垃圾回收,一个Region可能当前是老年代,做完一次GC之后变成新生代了,可能之前是新生代,GC之后变成老年代。Region的区域功能可能会动态变化。

默认新生代对堆内存的占比是5%,如果堆大小为4096M,那么新生代占据200MB左右的内存,对应大概是100个Region,可以通过-XX:G1NewSizePercent设置新生代初始占比,在系统运行中,JVM会不停的给新生代增加更多的Region,但是最多新生代的占比不会超过60%,可以通过-XX:G1MaxNewSizePercent调整。新生代中的Eden和Survivor对应的Region数量也跟之前一样,默认8:1:1,假设新生代现在有1000个Region,Eden区对应800个,S0对应100个,S1对应100个。

G1收集器中还有一个Humongous区域,专门用来存储大对象。

G1对大对象的定义:大小超过了一个Region容量一半的对象。

超过了整个Region容量的超级大对象,会被存放在N个连续的Humongous Region之中,G1的大多数行为都把Humongous Region作为老年代的一部分来进行看待。

Full GC的时候会回收新生代、老年代和Humongous区。

G1回收内存思路

G1收集器将Region作为单次回收的最小单元,即每次收集到的内存空间都是Region大小的整数倍。这样可以有计划地避免在整个Java堆中进行全区域的垃圾收集。

让G1收集器去跟踪各个Region里面的垃圾堆积的「价值」大小。

价值:即回收所获得的空间大小以及回收所需时间的经验值,在后台维护一个优先级列表,每次根据用户设定允许的GC停顿STW时间(使用参数-XX:MaxGCPauseMillis指定,默认值是200毫
秒),优先处理回收价值收益最大的那些Region。

3.3.2.1 使用方式

-XX:+UseG1GC

3.3.2.2 回收过程

类似CMS

  1. 初始标记:STW,暂停所有其他线程,记录GC Roots直接能引用的对象,速度很快,同CMS
  2. 并发标记:同CMS并发标记。不需要STW,从GC Root开始对堆中对象进行可达性分析,递归扫描整个堆里的对象图,找出要回收的对象。这阶段耗时较长,但可与用户程序并发执行。当对象图扫描完成以后,还要重新处理原始快照SATB记录下的在并发时有引用变动的对象。
  3. 最终标记:STW,解决多标漏标,使用的是原始快照。其余同CMS
  4. 筛选回收:STW
    a. 对各个Region的回收价值和成本进行排序,根据用户所期望的GC停顿STW时间(可以用JVM参数 -XX:MaxGCPauseMillis指定)来制定回收计划、
    设置JVM最大停顿时间-XX:MaxGCPauseMillis,是初始标记、最终标记、筛选回收三个STW的总和不超过这个值。如果垃圾太多在指定时间内回收不完,在筛选回收阶段可能不会完全回收。对回收时间估算,可能只回收一半或者三分之一,把时间控制在设定的时间内,剩余的区域下个阶段再回收。为了提升用户体验
    b. 使用标记-复制算法,把决定回收的那一部分Region的存活对象复制到空的Region中,再清理掉整个旧Region的全部空间。由多条收集器线程并行完成。

G1垃圾收集特点

  • G1收集器除了并发标记外,其余阶段都要完全暂停用户线程STW。
  • G1的回收机制是标记-复制,但是效果类似标记-整理。把标记的对象复制到相邻的空白的没有被使用过的Region,自己的Region直接清空。自身清空之后就可以变化了,之前是老年代,下次可能是新生代Eden。所以G1几乎没有内存碎片。但是大对象会使用连续的空间。
  • G1收集器在后台维护了一个优先列表,优先选择回收价值大的Region,比如一个Region花200ms能回收10M,另一个Region花50ms能回收20M,在回收时间有限的情况下,会优先选择后面这个Region进行回收。(判断存活对象的数量,存活的对象越多,需要复制的就越多,耗时越长)。这个时间不能胡乱设置,默认200ms,如果设置10ms,每次回收的内存非常少,最终导致满堆引发Full GC反而影响性能。

G1垃圾收集分类

  • 新生代收集 Yong GC
    之前学到的Eden区放满了会触发Minor GC,但是对于G1来说,5%的Eden区如果放满了会先判断清理时间是否接近配置的期望GC停顿时间-XX:MaxGCPauseMillis或者默认的200ms,如果远远小于这个值就不会在这时触发minorGC,而是继续往空白的Region中存放对象,使Region变成新的Eden区,直到判断清理时间接近200ms,才会触发minorGC。
  • 混合收集 Mixed GC
    不是Full GC,老年代的堆占有率达到参数-XX:InitiatingHeapOccupancyPercent设定的值则触发,回收所有的新生代和部分老年代。主要使用复制算法,如果没有足够的空Region能够承载拷贝对象,就会触发Full GC
  • 整堆收集 Full GC
    STW,用单线程进行标记、清理和压缩整理。

G1收集器参数

1. -XX:+UseG1GC:使用G1收集器
2. -XX:ParallelGCThreads:指定GC工作的线程数量
3. -XX:G1HeapRegionSize:指定分区大小(1MB~32MB,且必须是2的N次幂),默认将整堆划分为2048个Region
4. -XX:MaxGCPauseMillis:目标暂停时间(默认200ms)
5. -XX:G1NewSizePercent:新生代内存初始空间(默认整堆5%,值配置整数,默认就是百分比)
6. -XX:G1MaxNewSizePercent:新生代内存最大空间
7. -XX:TargetSurvivorRatio:Survivor区的填充容量(默认50%),Survivor区域里的一批对象(年龄1+年龄2+年龄n的多个年龄对象)总和超过了Survivor区域的50%,此时就会把年龄n(含)以上的对象都放入老年代
8. -XX:MaxTenuringThreshold:最大年龄阈值(默认15)
9. -XX:InitiatingHeapOccupancyPercent:老年代占用空间达到整堆内存阈值(默认45%),则执行新生代和老年代的Mixed GC,假如有100个格子,有45个老年代,触发Mixed GC
10. -XX:G1MixedGCLiveThresholdPercent: 回收Region的阈值,默认85%, Region中的存活对象低于这个值时才会回收该Region,如果超过这个值,存活对象过多,回收的的意义不大。假如这个Region中有100个对象,存活着85个,15个垃圾对象,就没必要回收。如果有只有30个存活对象,其他70个垃圾对象,就可以回收了。
11. -XX:G1MixedGCCountTarget:在一次回收过程中指定做几次筛选回收(默认8次),在最后一个筛选回收阶段可以回收一会儿,然后暂停回收,恢复系统运行,一会儿再开始回收,这样可以让系统不至于单次停顿时间过长。
12. -XX:G1HeapWastePercent:gc过程中空出来的Region是否充足阈值,默认5%,在混合回收的时候,对Region回收都是基于复制算法进行的,都是把要回收的Region里的存活对象放入其他Region,然后这个Region中的垃圾对象全部清理掉,这样的话在回收过程就会不断空出来新的Region,一旦空闲出来的Region数量达到了堆内存的5%,此时就会立即停止混合回收,意味着本次混合回收就结束了。

G1垃圾收集器使用场景

大内存(堆在8G以上)

● 50%以上的堆被存活对象占用
● 对象分配和晋升的速度变化非常大
● 垃圾回收时间特别长,超过1秒
● 8GB以上的堆内存(建议值)
● 停顿时间是500ms以内

3.3.3 ZGC

ZGC收集器是一款基于Region内存布局的,(暂时)不设分代的,以低延迟为首要目标的一款垃圾收集器,支持8MB-16TB级别的堆大小

ZGC内存布局
ZGC的Region具有动态性——动态创建和销毁,以及动态的区域容量大小。
ZGC的Region可以具有大、中、小三类容量。

  • 小型Region(Small Region):容量固定为2MB,用于放置小于256KB的小对象。
  • 中型Region(Medium Region):容量固定为32MB,用于放置大于等于256KB但小于4MB的对象。
  • 大型Region(Large Region):容量不固定,可以动态变化,但必须为2MB的整数倍,用于放置4MB或以上的大对象。每个大型Region中只会存放一个大对象,这也预示着虽然名字叫作「大型Region」,但它的实际容量完全有可能小于中型Region,最小容量可低至4MB。大型Region在ZGC的实现中是不会被重分配(重分配是ZGC的一种处理动作,用于复制对象的收集器阶段)的,因为复制一个大对象的代价非常高昂。

3.3.3.1 使用方式


3.3.3.2 回收过程

分为四个大的阶段。四个阶段都是并发执行的,仅是两个阶段中间会存在短暂的停顿小阶段

● 并发标记(Concurrent Mark):与G1一样,并发标记是遍历对象图做可达性分析的阶段,它的初始标记(Mark Start)和最终标记(Mark End)也会STW,与G1不同的是,ZGC的标记是在指针上而不是在对象上进行的,标记阶段会更新染色指针中的Marked 0、 Marked 1标志位。
● 并发预备重分配(Concurrent Prepare for Relocate):这个阶段需要根据特定的查询条件统计得出本次收集过程要清理哪些Region,将这些Region组成重分配集(Relocation Set)。ZGC每次回收都会扫描所有的Region,标记过程是针对全堆的,用范围更大的扫描成本换取省去G1中记忆集的维护成本。
● 并发重分配(Concurrent Relocate):重分配是ZGC执行过程中的核心阶段,这个过程要把重分配集中的存活对象复制到新的Region上,并为重分配集中的每个Region维护一个转发表(Forward Table),记录从旧对象到新对象的转向关系。
○ ZGC指针的「自愈」(Self-Healing):ZGC收集器能仅从引用上就明确得知一个对象是否处于重分配集之中。如果用户线程此时并发访问了位于重分配集中的对象,这次访问将会被预置的内存屏障(读屏障)所截获,然后立即根据Region上的转发表记录将访问转发到新复制的对象上,并同时修正更新该引用的值,使其直接指向新对象。
○ 只有第一次访问旧对象会陷入转发,也就是只慢一次。由于染色指针的存在,一旦重分配集中某个Region的存活对象都复制完毕后,这个Region就可以立即释放用于新对象的分配(但是转发表还得留着不能释放掉,因为可能还有访问在使用这个转发表),哪怕堆中还有很多指向这个对象的未更新指针也没有关系,这些旧指针一旦被使用,它们都可以自愈。
● 并发重映射(Concurrent Remap):重映射所做的就是修正整个堆中指向重分配集中旧对象的所有引用,但是ZGC中对象引用存在「自愈」功能,所以这个重映射操作并不是很迫切。ZGC很巧妙地把并发重映射阶段要做的工作,合并到了下一次垃圾收集循环中的并发标记阶段里去完成,反正它们都是要遍历所有对象的,这样合并就节省了一次遍历对象图的开销。一旦所有指针都被修正之后, 原来记录新旧对象关系的转发表就可以释放掉了。

四、如何选择垃圾收集器

  1. 优先调整堆的大小让服务器自己来选择
  2. 如果内存小于100M,使用串行收集器
  3. 如果是单核,并且没有停顿时间的要求,串行或JVM自己选择
  4. 如果允许停顿时间超过1秒,选择并行或者JVM自己选
  5. 如果响应时间最重要,并且不能超过1秒,使用并发收集器
  6. 4G以下可以用parallel,4-8G可以用ParNew+CMS,8G以上可以用G1,几百G以上用ZGC

JVM (二) 垃圾回收机制概念+垃圾回收器种类相关推荐

  1. JVM分代回收机制和垃圾回收算法

    JVM系列文章目录 初识JVM 深入理解JVM内存区域 玩转JVM对象和引用 JVM分代回收机制和垃圾回收算法 细谈JVM垃圾回收与部分底层实现 Class文件结构及深入字节码指令 玩转类加载和类加载 ...

  2. JVM架构、JVM垃圾回收机制、垃圾回收算法、垃圾回收器、JMM(内存模型)

    0 JVM和Java的关系 JDK = JRE + Java开发工具(java,javac,javadoc,javap-) JRE = JVM + Java核心类库 即: JDK = JVM + Ja ...

  3. JVM初学之JVM的垃圾回收机制与垃圾回收器

    如何判断对象是否"已死": 首先,我们要对对象进行垃圾回收之前,就必须要判断对象是否"已死",也就是是否可回收.这里有两种判断逻辑: 引用计数法: 在对象内部维 ...

  4. jvm垃圾回收机制_JVM 垃圾回收机制之堆的分代回收

    JVM垃圾回收机制之堆的分代回收 前言 前文我们了解了Java的GC机制,对于堆中的对象,JVM采用引用计数和可达性分析两种算法来标记对象是否可以清除,本文中我们还会了解到JVM将对分成了不同的区域, ...

  5. java对于垃圾回收机制[GC垃圾回收机制] 为什么有GC还会有内存溢出呢?

    java垃圾回收机制 来源于书本和工作中的总结. 内存泄露 如果分配出去的内存得不到释放,及时回收,就会引起系统运行速度下降,甚至导致程序瘫痪,这就是内存泄露 GC机制 java内存分配和回收 都是j ...

  6. python中垃圾回收机制_python 垃圾回收机制

    首先我们要说是 以引用计数为主 标记清楚和分代回收为辅 接下来分以下几个方面解释 一 引用计数 每个对象内部都维护了一个值,该值记录这此对象被引用的次数,如果次数为0,则Python垃圾回收机制会自动 ...

  7. 垃圾回收机制?垃圾回收的流程?

    垃圾回收机制? Java中,一个显著地特点是引入了垃圾回收机制,编写程序时,不再需要考虑内存管理,有效的防止内存泄露,提高内存的内存率. 垃圾回收器通常作为一个单独的低级线程运行,不可预知的情况下,对 ...

  8. php7垃圾回收机制l_PHP7 垃圾回收机制(GC)解析

    垃圾回收机制 垃圾回收机制是一种动态存储分配方案.它会自动释放程序不再需要的已分配的内存块. 自动回收内存的过程叫垃圾收集.垃圾回收机制可以让程序员不必过分关心程序内存分配,从而将更多的精力投入到业务 ...

  9. JS 垃圾回收机制以及垃圾回收策略

    垃圾回收机制 什么是垃圾回收机制: 解释:执行环境负责管理代码执行过程中使用的内存.JS的垃圾回收机制是为了以防内存泄漏,简单来说就是:间歇的不定期的寻找到不再使用的变量,并释放掉它们所指向的内存. ...

最新文章

  1. Lucene核心数据结构——FST存词典,跳表存倒排或者roarning bitmap 见另外一个文章...
  2. 4springboot:日志(上)
  3. stm32捕获占空比_基于STM32超声波避障小车
  4. windows平台下:scikit-learn安装教程
  5. 行动力决定了一个人的成败,有想法,就去做! C#的内存管理原理解析+标准Dispose模式的实现
  6. 解决:java.lang.IllegalStateException: ApplicationEventMulticaster not initialized
  7. 陌屿授权系统V2.0全解
  8. oracle database link创建
  9. Leetcode每日一题:66.plus-one(加一)
  10. Unity 2D和3D对象的点击
  11. 人脸检测(十二)--DDFD算法
  12. windows下使用vim
  13. a form 出口享惠情况_关于“出口享惠情况”如何填报?
  14. java图片二值化_实现图像的二值化(java+opencv)
  15. 4×4键盘板:ATMEGA328接口
  16. SSO单点登录原理详解(从入门到精通)
  17. windows下ping端口
  18. TFN DG15M 高抗干扰电缆故障测试仪评测
  19. NCBI推出blastp加速服务(Accelerated protein-protein BLAST)
  20. mysql按照年龄区间分组查询

热门文章

  1. 真无线蓝牙耳机性价比高?真无线蓝牙耳机性价比排行
  2. 元数据管理——企业数据治理的基石
  3. 第九届玲珑轻院校赛随笔
  4. 谷歌浏览器安装vue-devtools
  5. 2022爱分析・智慧园区厂商全景报告 | 爱分析报告
  6. 冬色烂漫 纯情踏雪 论著名画家冯庆冰雪画作品
  7. 漫话最短路径(二)--bellman-Ford(贝尔曼-福特)算法
  8. 微信第三方平台之代开发小程序(二)
  9. 用计算机弹咱们结婚吧乐谱,用计算器弹奏“周杰伦”,这些乐谱也太简单了吧!...
  10. oracle如何新建用户