java垃圾收集的算法

2020-10-28 13:43发布

7条回答
那些年很冒险的梦。
2楼 · 2020-10-28 15:19

1、标记-清除算法

  标记清除算法分为“标记”和“清除”两个阶段,首先先标记出那些对象需要被回收,在标记完成后会对这些被标记了的对象进行回收;

2、复制算法

  复制算法是将内存分为两块大小一样的区域,每次是使用其中的一块。当这块内存块用完了,就将这块内存中还存活的对象复制到另一块内存中,然后清空这块内存。这种算法在对象存活率较低的场景下效率很高,比如说新生代,只对整块内存区域的一半进行垃圾回收,在垃圾回收的过程也不会出现内存碎片的情况,不需要移动对象,只需要移动指针即可,实现简单,所以运行效率很高。运行效率是在建立在浪费空间的基础上的,这是典型的已空间换时间的方法,因为每次只能是使用北村的一半。

3、标记-整理算法

  复制算法在对象存活率较高的情况下就要进行较多的对象复制操作,效率将会变低。更关键的是,如果你不需要浪费50%的空间,就需要有额外的空间进行分配担保,用以应对被使用的内存中所有对象都100%存活的极端情况,所以在老年代一般不能直接选用这种办法。

4、分代收集算法

  分代收集算法将heap区域划分为新生代和老年代,新生代的空间比老年代的空间要小。新生代又分为了Eden和两个survivor空间,它们的比例为8:1:1。对象被创建时,内存的分配是在新生代的Eden区发生的,大对象直接在老年代分配内存,IBM的研究表明,Eden区98%的对象都是很快消亡的。


@CcCc
3楼 · 2020-10-28 15:32

1、标记-清除算法

  标记清除算法分为“标记”和“清除”两个阶段,首先先标记出那些对象需要被回收,在标记完成后会对这些被标记了的对象进行回收;

2、复制算法

  复制算法是将内存分为两块大小一样的区域,每次是使用其中的一块。当这块内存块用完了,就将这块内存中还存活的对象复制到另一块内存中,然后清空这块内存。这种算法在对象存活率较低的场景下效率很高,比如说新生代,只对整块内存区域的一半进行垃圾回收,在垃圾回收的过程也不会出现内存碎片的情况,不需要移动对象,只需要移动指针即可,实现简单,所以运行效率很高。运行效率是在建立在浪费空间的基础上的,这是典型的已空间换时间的方法,因为每次只能是使用北村的一半。

3、标记-整理算法

  复制算法在对象存活率较高的情况下就要进行较多的对象复制操作,效率将会变低。更关键的是,如果你不需要浪费50%的空间,就需要有额外的空间进行分配担保,用以应对被使用的内存中所有对象都100%存活的极端情况,所以在老年代一般不能直接选用这种办法。

4、分代收集算法

  分代收集算法将heap区域划分为新生代和老年代,新生代的空间比老年代的空间要小。新生代又分为了Eden和两个survivor空间,它们的比例为8:1:1。对象被创建时,内存的分配是在新生代的Eden区发生的,大对象直接在老年代分配内存,IBM的研究表明,Eden区98%的对象都是很快消亡的。


樱田妮妮NiNi
4楼 · 2020-10-28 17:11

1、 引用计数法(Reference Counting Collector)

引用计数法是唯一没有使用根集的垃圾回收的法,该算法使用引用计数器来区分存活对象和不再使用的对象。一般来说,堆中的每个对象对应一个引用计数器。当每一次创建一个对象并赋给一个变量时,引用计数器置为1。当对象被赋给任意变量时,引用计数器每次加1当对象出了作用域后(该对象丢弃不再使用),引用计数器减1,一旦引用计数器为0,对象就满足了垃圾收集的条件。

基于引用计数器的垃圾收集器运行较快,不会长时间中断程序执行,适宜地必须 实时运行的程序。但引用计数器增加了程序执行的开销,因为每次对象赋给新的变量,计数器加1,而每次现有对象出了作用域生,计数器减1。

2、tracing算法(Tracing Collector)

tracing算法是为了解决引用计数法的问题而提出,它使用了根集的概念。基于tracing算法的垃圾收集器从根集开始扫描,识别出哪些对象可达,哪些对象不可达,并用某种方式标记可达对象,例如对每个可达对象设置一个或多个位。在扫描识别过程中,基于tracing算法的垃圾收集也称为标记和清除(mark-and-sweep)垃圾收集器.

3、compacting算法(Compacting Collector)

为了解决堆碎片问题,基于tracing的垃圾回收吸收了Compacting算法的思想,在清除的过程中,算法将所有的对象移到堆的一端,堆的另一端就变成了一个相邻的空闲内存区,收集器会对它移动的所有对象的所有引用进行更新,使得这些引用在新的位置能识别原来 的对象。在基于Compacting算法的收集器的实现中,一般增加句柄和句柄表。

4、copying算法(Coping Collector)

该算法的提出是为了克服句柄的开销和解决堆碎片的垃圾回收。它开始时把堆分成 一个对象 面和多个空闲面, 程序从对象面为对象分配空间,当对象满了,基于coping算法的垃圾 收集就从根集中扫描活动对象,并将每个 活动对象复制到空闲面(使得活动对象所占的内存之间没有空闲洞),这样空闲面变成了对象面,原来的对象面变成了空闲面,程序会在新的对象面中分配内存。

一种典型的基于coping算法的垃圾回收是stop-and-copy算法,它将堆分成对象面和空闲区域面,在对象面与空闲区域面的切换过程中,程序暂停执行。

5、generation算法(Generational Collector)

stop-and-copy垃圾收集器的一个缺陷是收集器必须复制所有的活动对象,这增加了程序等待时间,这是coping算法低效的原因。在程序设计中有这样的规律:多数对象存在的时间比较短,少数的存在时间比较长。因此,generation算法将堆分成两个或多个,每个子堆作为对象的一代(generation)。由于多数对象存在的时间比较短,随着程序丢弃不使用的对象,垃圾收集器将从最年轻的子堆中收集这些对象。在分代式的垃圾收集器运行后,上次运行存活下来的对象移到下一最高代的子堆中,由于老一代的子堆不会经常被回收,因而节省了时间。

6、adaptive算法(Adaptive Collector)

在特定的情况下,一些垃圾收集算法会优于其它算法。基于Adaptive算法的垃圾收集器就是监控当前堆的使用情况,并将选择适当算法的垃圾收集器。


猜不到结尾
5楼 · 2020-10-29 09:23

大多数垃圾回收算法使用了根集(root set)这个概念;所谓根集就量正在执行的Java程序可以访问的引用变量的集合(包括局部变量、参数、类变量),程序可以使用引用变量访问对象的属性和调用对象的方法。垃圾收集首选需要确定从根开始哪些是可达的和哪些是不可达的,从根集可达的对象都是活动对象,它们不能作为垃圾被回收,这也包括从根集间接可达的对象。而根集通过任意路径不可达的对象符合垃圾收集的条件,应该被回收。下面介绍几个常用的算法。

1、 引用计数法(Reference Counting Collector)

引用计数法是唯一没有使用根集的垃圾回收的法,该算法使用引用计数器来区分存活对象和不再使用的对象。一般来说,堆中的每个对象对应一个引用计数器。当每一次创建一个对象并赋给一个变量时,引用计数器置为1。当对象被赋给任意变量时,引用计数器每次加1当对象出了作用域后(该对象丢弃不再使用),引用计数器减1,一旦引用计数器为0,对象就满足了垃圾收集的条件。

基于引用计数器的垃圾收集器运行较快,不会长时间中断程序执行,适宜地必须 实时运行的程序。但引用计数器增加了程序执行的开销,因为每次对象赋给新的变量,计数器加1,而每次现有对象出了作用域生,计数器减1。

2、tracing算法(Tracing Collector)

tracing算法是为了解决引用计数法的问题而提出,它使用了根集的概念。基于tracing算法的垃圾收集器从根集开始扫描,识别出哪些对象可达,哪些对象不可达,并用某种方式标记可达对象,例如对每个可达对象设置一个或多个位。在扫描识别过程中,基于tracing算法的垃圾收集也称为标记和清除(mark-and-sweep)垃圾收集器.

3、compacting算法(Compacting Collector)

为了解决堆碎片问题,基于tracing的垃圾回收吸收了Compacting算法的思想,在清除的过程中,算法将所有的对象移到堆的一端,堆的另一端就变成了一个相邻的空闲内存区,收集器会对它移动的所有对象的所有引用进行更新,使得这些引用在新的位置能识别原来 的对象。在基于Compacting算法的收集器的实现中,一般增加句柄和句柄表。

4、copying算法(Coping Collector)

该算法的提出是为了克服句柄的开销和解决堆碎片的垃圾回收。它开始时把堆分成 一个对象 面和多个空闲面, 程序从对象面为对象分配空间,当对象满了,基于coping算法的垃圾 收集就从根集中扫描活动对象,并将每个 活动对象复制到空闲面(使得活动对象所占的内存之间没有空闲洞),这样空闲面变成了对象面,原来的对象面变成了空闲面,程序会在新的对象面中分配内存。

一种典型的基于coping算法的垃圾回收是stop-and-copy算法,它将堆分成对象面和空闲区域面,在对象面与空闲区域面的切换过程中,程序暂停执行。

5、generation算法(Generational Collector)

stop-and-copy垃圾收集器的一个缺陷是收集器必须复制所有的活动对象,这增加了程序等待时间,这是coping算法低效的原因。在程序设计中有这样的规律:多数对象存在的时间比较短,少数的存在时间比较长。因此,generation算法将堆分成两个或多个,每个子堆作为对象的一代(generation)。由于多数对象存在的时间比较短,随着程序丢弃不使用的对象,垃圾收集器将从最年轻的子堆中收集这些对象。在分代式的垃圾收集器运行后,上次运行存活下来的对象移到下一最高代的子堆中,由于老一代的子堆不会经常被回收,因而节省了时间。



kitidog2016
6楼 · 2020-10-29 09:25

垃圾回收器GC(Garbage Collection)

  一、引用计数算法(Reference Counting)

  介绍:给对象添加一个引用计数器,每当一个地方引用它时,数据器加1;当引用失效时,计数器减1;计数器为0的即可被回收。

  优点:实现简单,判断效率高

  缺点:很难解决对象之间的相互循环引用(objA.instance = objB; objB.instance = objA)的问题,所以java语言并没有选用引用计数法管理内存

  二、根搜索算法(GC Root Tracing)

  Java和C#都是使用根搜索算法来判断对象是否存活。通过一系列的名为“GC Root”的对象作为起始点,从这些节点开始向下搜索,搜索所有走过的路径称为引用链(Reference Chain),当一个对象到GC Root没有任何引用链相连时(用图论来说就是GC Root到这个对象不可达时),证明该对象是可以被回收的。

  在Java中哪些对象可以成为GC Root?

  • 虚拟机栈(栈帧中的本地变量表)中的引用对象

  • 方法区中的类静态属性引用的对象

  • 方法区中的常量引用对象

  • 本地方法栈中JNI(即Native方法)的引用对象

  

  三、标记-清除算法(Mark-Sweep)

    首先标记出需要回收的对象,在标记完成后统一回收掉所有的被标记对象。

    缺点:效率问题和空间问题(标记清除后会产生大量的不连续内存碎片,内存碎片过多可能会导致程序需要分配较大对象时找不到足够大的连续内存空间而不得不提前触发另一次垃圾回收动作)

    

  四、复制算法(Copying)

    将内存划分为大小相等的两块,每次只使用其中的一块。当这块内存用完了,就将还存活的对象复制到另一块内存上,然后把已使用过的内存空间一次清理掉。

    优点:每次只对其中一块进行GC,不用考虑内存碎片的问题,并且实现简单,运行高效

    缺点:内存缩小了一半

    

    注:现在的商业虚拟机都是用这种收集算法回收新生代。内存分为一块较大的Eden空间和两块较小的Survior空间,每次使用Eden和其中的一块Survior.当回收时,将Eden和Survior中还存活的对象一次性拷贝到另外一块Survior空间上,最后清理Eden和刚才用过的Survior空间。

  五、标记-整理算法(Mark-Compact)

    让所有存活对象都向一端移动,然后直接清理掉端边界以外的所有内存。

    

    六、分代收集算法(Generational Collection)

      根据对象的存活周期的不同将内存划分为几块,一般就分为新生代和老年代,根据各个年代的特点采用不同的收集算法。新生代(少量存活)用复制算法,老年代(对象存活率高)“标记-清理”算法

    补充:分代划分内存介绍

    整个JVM内存总共划分为三代:年轻代(Young Generation)、年老代(Old Generation)、持久代(Permanent Generation)

    1、年轻代:所有新生成的对象首先都放在年轻代内存中。年轻代的目标就是尽可能快速的手机掉那些生命周期短的对象。年轻代内存分为一块较大的Eden空间和两块较小的Survior空间,每次使用Eden和其中的一块Survior.当回收时,将Eden和Survior中还存活的对象一次性拷贝到另外一块Survior空间上,最后清理Eden和刚才用过的Survior空间。

    2、年老代:在年轻代经历了N次GC后,仍然存活的对象,就会被放在老年代中。因此可以认为老年代存放的都是一些生命周期较长的对象。

    3、持久代:基本固定不变,用于存放静态文件,例如Java类和方法。持久代对GC没有显著的影响。持久代可以通过-XX:MaxPermSize=进行设置。

分类: JVM学习


魏魏姐
7楼 · 2020-10-29 09:41

1、垃圾收集器概述

垃圾收集器是垃圾回收算法(标记-清除算法、复制算法、标记-整理算法、火车算法)的具体实现,不同商家、不同版本的JVM所提供的垃圾收集器可能会有很在差别,本文主要介绍HotSpot虚拟机中的垃圾收集器。

1-1、垃圾收集器组合

JDK7/8后,HotSpot虚拟机所有收集器及组合(连线),如下图:

(A)、图中展示了7种不同分代的收集器:

Serial、ParNew、Parallel Scavenge、Serial Old、Parallel Old、CMS、G1;

(B)、而它们所处区域,则表明其是属于新生代收集器还是老年代收集器:

新生代收集器:Serial、ParNew、Parallel Scavenge;

老年代收集器:Serial Old、Parallel Old、CMS;

整堆收集器:G1;

(C)、两个收集器间有连线,表明它们可以搭配使用:

Serial/Serial Old、Serial/CMS、ParNew/Serial Old、ParNew/CMS、Parallel Scavenge/Serial Old、Parallel Scavenge/Parallel Old、G1;

(D)、其中Serial Old作为CMS出现"Concurrent Mode Failure"失败的后备预案(后面介绍);

1-2、并发垃圾收集和并行垃圾收集的区别

(A)、并行(Parallel)

指多条垃圾收集线程并行工作,但此时用户线程仍然处于等待状态;

如ParNew、Parallel Scavenge、Parallel Old;

(B)、并发(Concurrent)

指用户线程与垃圾收集线程同时执行(但不一定是并行的,可能会交替执行);

用户程序在继续运行,而垃圾收集程序线程运行于另一个CPU上;

如CMS、G1(也有并行);

1-3、Minor GC和Full GC的区别

(A)、Minor GC

又称新生代GC,指发生在新生代的垃圾收集动作;

因为Java对象大多是朝生夕灭,所以Minor GC非常频繁,一般回收速度也比较快;

(B)、Full GC

又称Major GC或老年代GC,指发生在老年代的GC;

出现Full GC经常会伴随至少一次的Minor GC(不是绝对,Parallel Sacvenge收集器就可以选择设置Major GC策略);

Major GC速度一般比Minor GC慢10倍以上;


楠楠楠楠
8楼 · 2020-10-29 14:22

1、垃圾收集器概述

垃圾收集器是垃圾回收算法(标记-清除算法、复制算法、标记-整理算法、火车算法)的具体实现,不同商家、不同版本的JVM所提供的垃圾收集器可能会有很在差别,本文主要介绍HotSpot虚拟机中的垃圾收集器。

1-1、垃圾收集器组合

JDK7/8后,HotSpot虚拟机所有收集器及组合(连线),如下图:

(A)、图中展示了7种不同分代的收集器:

Serial、ParNew、Parallel Scavenge、Serial Old、Parallel Old、CMS、G1;

(B)、而它们所处区域,则表明其是属于新生代收集器还是老年代收集器:

新生代收集器:Serial、ParNew、Parallel Scavenge;

老年代收集器:Serial Old、Parallel Old、CMS;

整堆收集器:G1;

(C)、两个收集器间有连线,表明它们可以搭配使用:

Serial/Serial Old、Serial/CMS、ParNew/Serial Old、ParNew/CMS、Parallel Scavenge/Serial Old、Parallel Scavenge/Parallel Old、G1;

(D)、其中Serial Old作为CMS出现"Concurrent Mode Failure"失败的后备预案(后面介绍);

1-2、并发垃圾收集和并行垃圾收集的区别

(A)、并行(Parallel)

指多条垃圾收集线程并行工作,但此时用户线程仍然处于等待状态;

如ParNew、Parallel Scavenge、Parallel Old;

(B)、并发(Concurrent)

指用户线程与垃圾收集线程同时执行(但不一定是并行的,可能会交替执行);

用户程序在继续运行,而垃圾收集程序线程运行于另一个CPU上;

如CMS、G1(也有并行);

1-3、Minor GC和Full GC的区别

(A)、Minor GC

又称新生代GC,指发生在新生代的垃圾收集动作;

因为Java对象大多是朝生夕灭,所以Minor GC非常频繁,一般回收速度也比较快;

(B)、Full GC

又称Major GC或老年代GC,指发生在老年代的GC;

出现Full GC经常会伴随至少一次的Minor GC(不是绝对,Parallel Sacvenge收集器就可以选择设置Major GC策略);

Major GC速度一般比Minor GC慢10倍以上;


相关问题推荐

  • 回答 2

    Statement的execute(String query)方法用来执行任意的SQL查询,如果查询的结果是一个ResultSet,这个方法就返回true。如果结果不是ResultSet,比如insert或者update查询,它就会返回false。我们可以通过它的getResultSet方法来获取ResultSet,或者通过getUpda...

  • 回答 22

    忙的时候项目期肯定要加班 但是每天加班应该还不至于

  • 回答 108
    已采纳

    虽然Java人才越来越多,但是人才缺口也是很大的,我国对JAVA工程师的需求是所有软件工程师当中需求大的,达到全部需求量的60%-70%,所以Java市场在短时间内不可能饱和。其次,Java市场不断变化,人才需求也会不断增加。马云说过,未来的制造业要的不是石油,...

  • 回答 5
    已采纳

    工信部证书含金量较高。工信部是国务院的下属结构,具有发放资质、证书的资格。其所发放的证书具有较强的权威性,在全国范围内收到认可,含金量通常都比较高。 工信部证书,其含义也就是工信部颁发并承认的某项技能证书,是具有法律效力的,并且是国家认可的...

  • 回答 70
    已采纳

    学Java好不好找工作?看学完Java后能做些什么吧。一、大数据技术Hadoop以及其他大数据处理技术都是用Java或者其他,例如Apache的基于Java 的 HBase和Accumulo以及ElasticSearchas。但是Java在此领域并未占太大空间,但只要Hadoop和ElasticSearchas能够成长壮...

  • 回答 16
    已采纳

    就是java的基础知识啊,比如Java 集合框架;Java 多线程;线程的五种状态;Java 虚拟机;MySQL (InnoDB);Spring 相关;计算机网络;MQ 消息队列诸如此类

  • 回答 12

    #{}和${}这两个语法是为了动态传递参数而存在的,是Mybatis实现动态SQL的基础,总体上他们的作用是一致的(为了动态传参),但是在编译过程、是否自动加单引号、安全性、使用场景等方面有很多不同,下面详细比较两者间的区别:1.#{} 是 占位符 :动态解析 ...

  • 回答 62

    没问题的,专科学历也能学习Java开发的,主要看自己感不感兴趣,只要认真学,市面上的培训机构不少都是零基础课程,能跟得上,或是自己先找些资料学习一下。

  • 回答 4

    1、反射对单例模式的破坏采用反射的方式另辟蹊径实例了该类,导致程序中会存在不止一个实例。解决方案其思想就是采用一个全局变量,来标记是否已经实例化过了,如果已经实例化过了,第 二次实例化的时候,抛出异常2、clone()对单例模式的破坏当需要实现单例的...

  • 回答 5

     优点: 一、实例控制  单例模式会阻止其他对象实例化其自己的单例对象的副本,从而确保所有对象都访问唯一实例。 二、灵活性  因为类控制了实例化过程,所以类可以灵活更改实例化过程。 缺点: 一、开销  虽然数量很少,但如果每次对象请求引用时都要...

  • 回答 4

    这个主要是看你数组的长度是多少, 比如之前写过的一个程序有个数组存的是各个客户端的ip地址:string clientIp[4]={XXX, xxx, xxx, xxx};这个时候如果想把hash值对应到上面四个地址的话,就应该对4取余,这个时候p就应该为4...

  • 回答 6

     哈希表的大小 · 关键字的分布情况 · 记录的查找频率 1.直接寻址法:取关键字或关键字的某个线性函数值为散列地址。即H(key)=key或H(key) = a·key + b,其中a和b为常数(这种散列函数叫做自身函数)。...

  • 回答 6

    哈希表的大小取决于一组质数,原因是在hash函数中,你要用这些质数来做模运算(%)。而分析发现,如果不是用质数来做模运算的话,很多生活中的数据分布,会集中在某些点上。所以这里最后采用了质数做模的除数。 因为用质数做了模的除数,自然存储空间的大小也用质数了...

  • 回答 2

    是啊,哈希函数的设计至关重要,好的哈希函数会尽可能地保证计算简单和散列地址分布均匀,但是,我们需要清楚的是,数组是一块连续的固定长度的内存空间

  • 回答 3

     解码查表优化算法,seo优化

  • 回答 5

    1.对对象元素中的关键字(对象中的特有数据),进行哈希算法的运算,并得出一个具体的算法值,这个值 称为哈希值。2.哈希值就是这个元素的位置。3.如果哈希值出现冲突,再次判断这个关键字对应的对象是否相同。如果对象相同,就不存储,因为元素重复。如果对象不同,就...

没有解决我的问题,去提问