GC算法详解

企业知识库AI助手的权限管理架构:如何实现细粒度控制? 在展开架构设计前,我们需要先明确“细粒度权限”的核心定义,并理解它对AI助手的特殊意义。权限管理的“粒度”,本质是权限控制的精准程度。维度粗粒度权限细粒度权限资源范围entire document(整个文档)field/paragraph(字段/段落)操作类型read/write(读/写)generate_summary/download/export(生成摘要/下载/导出)上下文约束无(静态权限)time/ip/device(时间/IP/设备)适用场景简单系统(如内部wiki) 阅读详情

本文主要内容:

  • GC的概念
  • GC算法

    引用计数法(无法解决循环引用的问题,不被java采纳)

      根搜索算法

      现代虚拟机中的垃圾搜集算法:

      标记-清除

      复制算法(新生代)

      标记-压缩(老年代)

      分代收集

  • Stop-The-World

 

一、GC的概念:

  • GC:Garbage Collection 垃圾收集
  • 1960年 Lisp使用了GC
  • Java中,GC的对象是Java堆和方法区(即永久区)

我们接下来对上面的三句话进行一一的解释:

(1)GC:Garbage Collection 垃圾收集。这里所谓的垃圾指的是在系统运行过程当中所产生的一些无用的对象,这些对象占据着一定的内存空间,如果长期不被释放,可能导致OOM。

在C/C++里是由程序猿自己去申请、管理和释放内存空间,因此没有GC的概念。而在Java中,后台专门有一个专门用于垃圾回收的线程来进行监控、扫描,自动将一些无用的内存进行释放,这就是垃圾收集的一个基本思想,目的在于防止由程序猿引入的人为的内存泄露。

(2)事实上,GC的历史比Java久远,1960年诞生于MIT的Lisp是第一门真正使用内存动态分配和垃圾收集技术的语言。当Lisp还在胚胎时期时,人们就在思考GC需要完成的3件事情:

哪些内存需要回收?

什么时候回收?

如何回收?

(3)内存区域中的程序计数器、虚拟机栈、本地方法栈这3个区域随着线程而生,线程而灭;栈中的栈帧随着方法的进入和退出而有条不紊地执行着出栈和入栈的操作,每个栈帧中分配多少内存基本是在类结构确定下来时就已知的。在这几个区域不需要过多考虑回收的问题,因为方法结束或者线程结束时,内存自然就跟着回收了。

而Java堆和方法区则不同,一个接口中的多个实现类需要的内存可能不同,一个方法中的多个分支需要的内存也可能不一样,我们只有在程序处于运行期间时才能知道会创建哪些对象,这部分内存的分配和回收都是动态的,GC关注的也是这部分内存,后面的文章中如果涉及到“内存”分配与回收也仅指着一部分内存。

 

二、引用计数算法:(老牌垃圾回收算法。无法处理循环引用,没有被Java采纳)

1、引用计数算法的概念:

给对象中添加一个引用计数器,每当有一个地方引用它时,计数器值就加1;当引用失效时,计数器值就减1;任何时刻计数器为0的对象就是不可能再被使用的。

e6217360-0985-46e8-88fd-022f1fc0fba5

2、使用者举例:

引用计数算法的实现简单,判定效率也高,大部分情况下是一个不错的算法。很多地方应用到它。例如:

微软公司的COM技术:Computer Object Model

使用ActionScript3的FlashPlayer

Python

但是,主流的java虚拟机并没有选用引用计数算法来管理内存,其中最主要的原因是:它很难解决对象之间相互循环引用的问题。

3、引用计数算法的问题:

  • 引用和去引用伴随加法和减法,影响性能
  • 致命的缺陷:对于循环引用的对象无法进行回收

1a489e67-e047-408f-a97e-4a141e6ab3b0

上面的3个图中,对于最右边的那张图而言:循环引用的计数器都不为0,但是他们对于根对象都已经不可达了,但是无法释放。

循环引用的代码举例:

 1 public class Object {
 2 
 3     Object field = null;
 4     
 5     public static void main(String[] args) {
 6         Thread thread = new Thread(new Runnable() {
 7             public void run() {
 8                 Object objectA = new Object();
 9                 Object objectB = new Object();//位置1
10                 objectA.field = objectB;
11                 objectB.field = objectA;//位置2
12                 //to do something
13                 objectA = null;
14                 objectB = null;//位置3
15             }
16         });
17         thread.start();
18         while (true);
19     }
20     
21 } 

上方代码看起来有点刻意为之,但其实在实际编程过程当中,是经常出现的,比如两个一对一关系的数据库对象,各自保持着对方的引用。最后一个无限循环只是为了保持JVM不退出,没什么实际意义。

代码解释:

代码中标注了1、2、3三个数字,当位置1的语句执行完以后,两个对象的引用计数全部为1。当位置2的语句执行完以后,两个对象的引用计数就全部变成了2。当位置3的语句执行完以后,也就是将二者全部归为空值以后,二者的引用计数仍然为1。根据引用计数算法的回收规则,引用计数没有归0的时候是不会被回收的。

对于我们现在使用的GC来说,当thread线程运行结束后,会将objectA和objectB全部作为待回收的对象。而如果我们的GC采用上面所说的引用计数算法,则这两个对象永远不会被回收,即便我们在使用后显示的将对象归为空值也毫无作用。

 

三、根搜索算法:

1、根搜索算法的概念:

  由于引用计数算法的缺陷,所以JVM一般会采用一种新的算法,叫做根搜索算法。它的处理方式就是,设立若干种根对象,当任何一个根对象到某一个对象均不可达时,则认为这个对象是可以被回收的。

7ab0f17b-13f7-4886-a24d-3813c2173891

如上图所示,ObjectD和ObjectE是互相关联的,但是由于GC roots到这两个对象不可达,所以最终D和E还是会被当做GC的对象,上图若是采用引用计数法,则A-E五个对象都不会被回收。

 

2、可达性分析:

 我们刚刚提到,设立若干种根对象,当任何一个根对象到某一个对象均不可达时,则认为这个对象是可以被回收的。我们在后面介绍标记-清理算法/标记整理算法时,也会一直强调从根节点开始,对所有可达对象做一次标记,那什么叫做可达呢?这里解释如下:

可达性分析:

  从根(GC Roots)的对象作为起始点,开始向下搜索,搜索所走过的路径称为“引用链”,当一个对象到GC Roots没有任何引用链相连(用图论的概念来讲,就是从GC Roots到这个对象不可达)时,则证明此对象是不可用的。

 

3、根(GC Roots):

说到GC roots(GC根),在JAVA语言中,可以当做GC roots的对象有以下几种:

1、栈(栈帧中的本地变量表)中引用的对象。

2、方法区中的静态成员。

3、方法区中的常量引用的对象(全局变量)

4、本地方法栈中JNI(一般说的Native方法)引用的对象。

注:第一和第四种都是指的方法的本地变量表,第二种表达的意思比较清晰,第三种主要指的是声明为final的常量值。

在根搜索算法的基础上,现代虚拟机的实现当中,垃圾搜集的算法主要有三种,分别是标记-清除算法、复制算法、标记-整理算法。这三种算法都扩充了根搜索算法,不过它们理解起来还是非常好理解的。

 

四、标记-清除算法:

1、标记清除算法的概念:

标记-清除算法是现代垃圾回收算法的思想基础。标记-清除算法将垃圾回收分为两个阶段:标记阶段和清除阶段。一种可行的实现是,在标记阶段,首先通过根节点,标记所有从根节点开始的可达对象。因此,未被标记的对象就是未被引用的垃圾对象;然后,在清除阶段,清除所有未被标记的对象。

7de44970-2e02-46a1-a5d0-0663b21906c6

2、标记-清除算法详解:

它的做法是当堆中的有效内存空间(available memory)被耗尽的时候,就会停止整个程序(也被成为stop the world),然后进行两项工作,第一项则是标记,第二项则是清除。

  • 标记:标记的过程其实就是,遍历所有的GC Roots,然后将所有GC Roots可达的对象标记为存活的对象。
  • 清除:清除的过程将遍历堆中所有的对象,将没有标记的对象全部清除掉。

也就是说,就是当程序运行期间,若可以使用的内存被耗尽的时候,GC线程就会被触发并将程序暂停,随后将依旧存活的对象标记一遍,最终再将堆中所有没被标记的对象全部清除掉,接下来便让程序恢复运行。

来看下面这张图:

47146934-c3a3-4976-991f-77e84ae008cc

上图代表的是程序运行期间所有对象的状态,它们的标志位全部是0(也就是未标记,以下默认0就是未标记,1为已标记),假设这会儿有效内存空间耗尽了,JVM将会停止应用程序的运行并开启GC线程,然后开始进行标记工作,按照根搜索算法,标记完以后,对象的状态如下图:

5cbf57ce-c83a-40d2-b58a-b37d3eee3803

上图中可以看到,按照根搜索算法,所有从root对象可达的对象就被标记为了存活的对象,此时已经完成了第一阶段标记。接下来,就要执行第二阶段清除了,那么清除完以后,剩下的对象以及对象的状态如下图所示:

8654ed59-fc00-446d-8995-a02ab57cf213

上图可以看到,没有被标记的对象将会回收清除掉,而被标记的对象将会留下,并且会将标记位重新归0。接下来就不用说了,唤醒停止的程序线程,让程序继续运行即可。

疑问:为什么非要停止程序的运行呢?

答:

这个其实也不难理解,假设我们的程序与GC线程是一起运行的,各位试想这样一种场景。

假设我们刚标记完图中最右边的那个对象,暂且记为A,结果此时在程序当中又new了一个新对象B,且A对象可以到达B对象。但是由于此时A对象已经标记结束,B对象此时的标记位依然是0,因为它错过了标记阶段。因此当接下来轮到清除阶段的时候,新对象B将会被苦逼的清除掉。如此一来,不难想象结果,GC线程将会导致程序无法正常工作。

上面的结果当然令人无法接受,我们刚new了一个对象,结果经过一次GC,忽然变成null了,这还怎么玩?

3、标记-清除算法的缺点:

(1)首先,它的缺点就是效率比较低(递归与全堆对象遍历),导致stop the world的时间比较长,尤其对于交互式的应用程序来说简直是无法接受。试想一下,如果你玩一个网站,这个网站一个小时就挂五分钟,你还玩吗?

(2)第二点主要的缺点,则是这种方式清理出来的空闲内存是不连续的,这点不难理解,我们的死亡对象都是随即的出现在内存的各个角落的,现在把它们清除之后,内存的布局自然会乱七八糟。而为了应付这一点,JVM就不得不维持一个内存的空闲列表,这又是一种开销。而且在分配数组对象的时候,寻找连续的内存空间会不太好找。

 

五、复制算法:(新生代的GC)

复制算法的概念:

将原有的内存空间分为两块,每次只使用其中一块,在垃圾回收时,将正在使用的内存中的存活对象复制到未使用的内存块中,之后,清除正在使用的内存块中的所有对象,交换两个内存的角色,完成垃圾回收。

  • 与标记-清除算法相比,复制算法是一种相对高效的回收方法
  • 不适用于存活对象较多的场合,如老年代(复制算法适合做新生代的GC)

ff1e1846-e49c-4663-aee1-7c63628f567c

  • 复制算法的最大的问题是:空间的浪费

复制算法使得每次都只对整个半区进行内存回收,内存分配时也就不用考虑内存碎片等复杂情况,只要移动堆顶指针,按顺序分配内存即可,实现简单,运行高效。只是这种算法的代价是将内存缩小为原来的一半,这个太要命了。

所以从以上描述不难看出,复制算法要想使用,最起码对象的存活率要非常低才行,而且最重要的是,我们必须要克服50%内存的浪费。

现在的商业虚拟机都采用这种收集算法来回收新生代,新生代中的对象98%都是“朝生夕死”的,所以并不需要按照1:1的比例来划分内存空间,而是将内存分为一块比较大的Eden空间和两块较小的Survivor空间,每次使用Eden和其中一块Survivor。当回收时,将Eden和Survivor中还存活着的对象一次性地复制到另外一块Survivor空间上,最后清理掉Eden和刚才用过的Survivor空间。HotSpot虚拟机默认Eden和Survivor的大小比例是8:1,也就是说,每次新生代中可用内存空间为整个新生代容量的90%(80%+10%),只有10%的空间会被浪费。

当然,98%的对象可回收只是一般场景下的数据,我们没有办法保证每次回收都只有不多于10%的对象存活,当Survivor空间不够用时,需要依赖于老年代进行分配担保,所以大对象直接进入老年代。整个过程如下图所示:

7e1f6ed2-e0c4-45e4-b7db-b59c28e1ee9c

上图中,绿色箭头的位置代表的是大对象,大对象直接进入老年代。

根据上面的复制算法,现在我们来看下面的这个gc日志的数字,就应该能看得懂了吧:

6d59301f-f0c9-4fed-ba36-e66bc6574e8f

上方GC日志中,新生代的可用空间是13824K(eden区的12288K+from space的1536K)。而根据内存的地址计算得知,新生代的总空间为15M,而这个15M的空间是 = 13824K +to space 的 1536K。

 

六、标记-整理算法:(老年代的GC)

引入:

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

概念:

标记-压缩算法适合用于存活对象较多的场合,如老年代。它在标记-清除算法的基础上做了一些优化。和标记-清除算法一样,标记-压缩算法也首先需要从根节点开始,对所有可达对象做一次标记;但之后,它并不简单的清理未标记的对象,而是将所有的存活对象压缩到内存的一端;之后,清理边界外所有的空间。

cc79889a-0856-4018-92c3-c51108c9caea

  • 标记:它的第一个阶段与标记/清除算法是一模一样的,均是遍历GC Roots,然后将存活的对象标记。
  • 整理:移动所有存活的对象,且按照内存地址次序依次排列,然后将末端内存地址以后的内存全部回收。因此,第二阶段才称为整理阶段。

上图中可以看到,标记的存活对象将会被整理,按照内存地址依次排列,而未被标记的内存会被清理掉。如此一来,当我们需要给新对象分配内存时,JVM只需要持有一个内存的起始地址即可,这比维护一个空闲列表显然少了许多开销。

标记/整理算法不仅可以弥补标记/清除算法当中,内存区域分散的缺点,也消除了复制算法当中,内存减半的高额代价。

  • 但是,标记/整理算法唯一的缺点就是效率也不高。

不仅要标记所有存活对象,还要整理所有存活对象的引用地址。从效率上来说,标记/整理算法要低于复制算法。

标记-清除算法、复制算法、标记整理算法的总结:

三个算法都基于根搜索算法去判断一个对象是否应该被回收,而支撑根搜索算法可以正常工作的理论依据,就是语法中变量作用域的相关内容。因此,要想防止内存泄露,最根本的办法就是掌握好变量作用域,而不应该使用C/C++式内存管理方式。

在GC线程开启时,或者说GC过程开始时,它们都要暂停应用程序(stop the world)。

它们的区别如下:(>表示前者要优于后者,=表示两者效果一样)

(1)效率:复制算法>标记/整理算法>标记/清除算法(此处的效率只是简单的对比时间复杂度,实际情况不一定如此)。

(2)内存整齐度:复制算法=标记/整理算法>标记/清除算法。

(3)内存利用率:标记/整理算法=标记/清除算法>复制算法。

注1:可以看到标记/清除算法是比较落后的算法了,但是后两种算法却是在此基础上建立的。

注2:时间与空间不可兼得。

 

七、分代收集算法:(新生代的GC+老年代的GC)

当前商业虚拟机的GC都是采用的“分代收集算法”,这并不是什么新的思想,只是根据对象的存活周期的不同将内存划分为几块儿。一般是把Java堆分为新生代和老年代:短命对象归为新生代,长命对象归为老年代。

  • 少量对象存活,适合复制算法:在新生代中,每次GC时都发现有大批对象死去,只有少量存活,那就选用复制算法,只需要付出少量存活对象的复制成本就可以完成GC。
  • 大量对象存活,适合用标记-清理/标记-整理:在老年代中,因为对象存活率高、没有额外空间对他进行分配担保,就必须使用“标记-清理”/“标记-整理”算法进行GC。

注:老年代的对象中,有一小部分是因为在新生代回收时,老年代做担保,进来的对象;绝大部分对象是因为很多次GC都没有被回收掉而进入老年代。

八、可触及性:

所有的算法,需要能够识别一个垃圾对象,因此需要给出一个可触及性的定义。

可触及的:

  从根节点可以触及到这个对象。

      其实就是从根节点扫描,只要这个对象在引用链中,那就是可触及的。

可复活的:

  一旦所有引用被释放,就是可复活状态

  因为在finalize()中可能复活该对象

不可触及的:

  在finalize()后,可能会进入不可触及状态

  不可触及的对象不可能复活

      要被回收。

finalize方法复活对象的代码举例:

 1 package test03;
 2 
 3 /**
 4  * Created by smyhvae on 2015/8/19.
 5  */
 6 public class CanReliveObj {
 7     public static CanReliveObj obj;
 8 
 9     //当执行GC时,会执行finalize方法,并且只会执行一次
10     @Override
11     protected void finalize() throws Throwable {
12         super.finalize();
13         System.out.println("CanReliveObj finalize called");
14         obj = this;   //当执行GC时,会执行finalize方法,然后这一行代码的作用是将null的object复活一下,然后变成了可触及性
15     }
16 
17     @Override
18     public String toString() {
19         return "I am CanReliveObj";
20     }
21 
22     public static void main(String[] args) throws
23             InterruptedException {
24         obj = new CanReliveObj();
25         obj = null;   //可复活
26         System.out.println("第一次gc");
27         System.gc();
28         Thread.sleep(1000);
29         if (obj == null) {
30             System.out.println("obj 是 null");
31         } else {
32             System.out.println("obj 可用");
33         }
34         obj = null;    //不可复活
35         System.out.println("第二次gc");
36         System.gc();
37         Thread.sleep(1000);
38         if (obj == null) {
39             System.out.println("obj 是 null");
40         } else {
41             System.out.println("obj 可用");
42         }
43     }
44 }

 

我们需要注意第14行的注释。一开始,我们在第25行将obj设置为null,然后执行一次GC,本以为obj会被回收掉,其实并没有,因为GC的时候会调用11行的finalize方法,然后obj在第14行被复活了。紧接着又在第34行设置obj设置为null,然后执行一次GC,此时obj就被回收掉了,因为finalize方法只会执行一次。

31011217-d3a2-4e5b-9503-4f0b9bad9161

finalize方法的使用总结:

  • 经验:避免使用finalize(),操作不慎可能导致错误。
  • 优先级低,何时被调用,不确定

何时发生GC不确定,自然也就不知道finalize方法什么时候执行

  • 如果要使用finalize去释放资源,我们可以使用try-catch-finally来替代它

 

九、Stop-The-World:

1、Stop-The-World概念:

  Java中一种全局暂停的现象。

全局停顿,所有Java代码停止,native代码可以执行,但不能和JVM交互

多半情况下是由于GC引起。

    少数情况下由其他情况下引起,如:Dump线程、死锁检查、堆Dump。

 

2、GC时为什么会有全局停顿?

    (1)避免无法彻底清理干净

打个比方:类比在聚会,突然GC要过来打扫房间,聚会时很乱,又有新的垃圾产生,房间永远打扫不干净,只有让大家停止活动了,才能将房间打扫干净。

    况且,如果没有全局停顿,会给GC线程造成很大的负担,GC算法的难度也会增加,GC很难去判断哪些是垃圾。

  (2)GC的工作必须在一个能确保一致性的快照中进行。

这里的一致性的意思是:在整个分析期间整个执行系统看起来就像被冻结在某个时间点上,不可以出现分析过程中对象引用关系还在不断变化的情况,该点不满足的话分析结果的准确性无法得到保证。

这点是导致GC进行时必须停顿所有Java执行线程的其中一个重要原因。

3、Stop-The-World的危害:

长时间服务停止,没有响应(将用户正常工作的线程全部暂停掉)

遇到HA系统,可能引起主备切换,严重危害生产环境。

  备注:HA:High Available, 高可用性集群。

d07bb3ea-1235-41d5-9fb1-56b4087d1acf

比如上面的这主机和备机:现在是主机在工作,此时如果主机正在GC造成长时间停顿,那么备机就会监测到主机没有工作,于是备机开始工作了;但是主机不工作只是暂时的,当GC结束之后,主机又开始工作了,那么这样的话,主机和备机就同时工作了。主机和备机同时工作其实是非常危险的,很有可能会导致应用程序不一致、不能提供正常的服务等,进而影响生产环境。

代码举例:

(1)打印日志的代码:(每隔100ms打印一条)

public static class PrintThread extends Thread{
    public static final long starttime=System.currentTimeMillis();
    @Override
    public void run(){
        try{
            while(true){
                long t=System.currentTimeMillis()-starttime;
                System.out.println("time:"+t);
                Thread.sleep(100);
            }
        }catch(Exception e){

        }
    }
}

 

上方代码中,是负责打印日志的代码,每隔100ms打印一条,并计算打印的时间。

(2)工作线程的代码:(工作线程,专门用来消耗内存)

public static class MyThread extends Thread{
    HashMap<Long,byte[]> map=new HashMap<Long,byte[]>();
    @Override
    public void run(){
        try{
            while(true){
                if(map.size()*512/1024/1024>=450){   //如果map消耗的内存消耗大于450时,那就清理内存
                    System.out.println("=====准备清理=====:"+map.size());
                    map.clear();
                }

                for(int i=0;i<1024;i++){
                    map.put(System.nanoTime(), new byte[512]);
                }
                Thread.sleep(1);
            }
        }catch(Exception e){
            e.printStackTrace();
        }
    }
}

 

然后,我们设置gc的参数为:

-Xmx512M -Xms512M -XX:+UseSerialGC -Xloggc:gc.log -XX:+PrintGCDetails -Xmn1m -XX:PretenureSizeThreshold=50 -XX:MaxTenuringThreshold=1

 

打印日志如下:

8a8de388-7989-47f2-a7e1-496487e4be57

上图中,红色字体代表的正在GC。按道理来说,应该是每隔100ms会打印输出一条日志,但是当执行GC的时候,会出现全局停顿的情况,导致没有按时输出。

【深度学习|多实例学习】多实例学习(Multiple Instance Learning, MIL)的起源、发展和应用,附代码(一) 阅读详情

相关推荐

疾病负担研究(GBD)——如何使用joinpoint软件计算AAPC

疾病负担研究(GBD)——如何使用joinpoint软件计算AAPC

weixin_44240228的博客 1万+

GC 三大算法

三大 GC 算法的学习与理解

m0_50888347的博客 2419

跨模态行人重识别实战:Python复现SYSU-MM01官方评估协议

本文详细介绍了如何用Python复现SYSU-MM01数据集的官方评估协议,以解决原Matlab代码在Python生态中不便使用的问题。文章深入解析了数据集的`indoor`与`all`两种评估模式,并提供了完整的Python代码实现,包括特征加载、相似度计算、Rank-k与mAP指标计算等核心步骤,确保评估结果与官方Matlab版本完全一致,助力跨模态行人重识别研究。

weixin_29081163的博客 99

【JVM】一文搞懂常见GC算法

GC目的程序运行过程中可能会产生许多垃圾对象,持续占用内存会造成内存泄漏,最终可能导致内存溢出,迫使系统中断运行。首先需要搞懂内存泄漏和内存溢出的概念!!!内存泄漏(memoryleak)是指程序在申请内存后,无法释放已申请的内存空间,导致系统无法及时回收内存并且分配给其他进程使用。通常少次数的内存无法及时回收并不会到程序造成什么影响,但是如果在内存本身就比较少获取多次导致内存无法正常回收时,就会导致内存不够用,最终导致内存溢出。内存溢出(outofmemory)。)。)。内存效率。。.........

fearless的博客 6030

linux 内核vxlan收发包流程

1.vxlan口收包处理流程 前面几章详细介绍了vxlan接口的使用,而且已经知道vxlan是 MAC IN UDP中的封装,因此,在解封装之前,一切按照原有流程走,在此复习一下内核收发包流程(驱动层的数据处理这次不再解析,直接从__netif_receive_skb_core开始) #物理网卡处理中断,触发softirq i40e_intr └─napi_schedule_irqoff #i40e softirq把包放到per cpu backlog,触发softirq i40e_napi_p

魏言华的博客 3826

千兆以太网 PCB 设计实战:4层板 100Ω 差分对布线,EMI 降低 6dB 实测

本文详细解析了千兆以太网 PCB 设计中的关键技术与实战经验,重点介绍了4层板上100Ω差分对的优化布线方法,通过实测数据展示了EMI降低6dB的有效方案。内容涵盖层叠设计、阻抗计算、布线技巧及EMI抑制措施,为硬件工程师提供了一套完整的高速电路设计解决方案。

weixin_29175469的博客 426

GC四大算法

目录 什么是GC GC四大算法 前奏: 可达性分析 什么是大对象: 方法区如何判断是否需要回收 正文 引用计数法(JVM一般不采取这种算法) 复制算法(copying)(年轻代使用) 标记-清除算法(Mark-Sweep)(老年代使用) 标记整理算法(Mark-Compact)(老年代使用) 标记-清除-压缩(Mark-Sweep(标记清除算法)+Mark-C...

小白鼠丶 2794

导航系统 | 全球四大卫星导航系统(2025)核心能力对比分析

北斗系统通过GEO卫星(80°E、110.5°E、140°E)实现区域增强,其IGSO卫星在亚太地区形成"8"字形轨迹,使该区域可见卫星数量比GPS多4-6颗,显著提升复杂环境下的定位可用性[13]。北斗短报文功能在2025年云南地震救援中发挥关键作用,被困人员通过北斗终端发送120字求救信息,实现"位置+状态"一体化上报,救援响应时间缩短40%[15]。北斗通过三频信号(B1C/B2a/B3)消除电离层延迟误差,在城市峡谷环境下定位连续性达99.98%,优于GPS的99.95%[5]。

尘世冰封的专栏 2614

JVM的四种GC算法

介绍 程序在运行过程中,会产生大量的内存垃圾(一些没有引用指向的内存对象都属于内存垃圾,因为这些对象已经无法访问,程序用不了它们了,对程序而言它们已经死亡),为了确保程序运行时的性能,java虚拟机在程序运行的过程中不断地进行自动的垃圾回收(GC)。关于 JVM 的 GC 算法主要有下面四种: 引用计数算法(Reference counting) 算法思想: 每个对象在创建的时候,就给...

黑白沙漠 1万+

Microsemi Libero系列教程(二)——新建点灯工程

前言 上一篇文章,介绍了Microsemi Libero系列教程(一)-Libero开发环境介绍,下载,安装与注册,作为嵌入式开发中的Hello World,点灯是再也基础不过的实验了,通过点灯实验,可以了解芯片GPIO的控制和开发环境IDE新建工程的流程,对于FPGA来说,每个IO口几乎一样,所以本篇文章主要学习一下如何基于Microsemi Libero集成开发环境建立一个示例工程,让一个L...

whik1194的博客 1万+

Python 爬虫进阶技巧:定时爬虫任务实现无人值守采集

常规爬虫多依赖手动触发脚本运行,单次采集完成后需人工二次启动,无法满足日常周期性数据监控、行情抓取、资讯同步、业务台账定时归档等常态化采集需求。搭建可自主调度、自动启停、周期循环的定时爬虫任务,脱离人工干预实现无人值守全自动采集,是爬虫从临时脚本走向工程化落地的关键一步。schedule 轻量定时库官方文档APScheduler 高级定时框架官方文档Python time 内置模块官方文档Linux crontab 定时任务官方手册。

2503_91057718的博客 1117

Java虚拟机详解04----GC算法和种类【重要】

  【声明】  欢迎转载,但请保留文章原始出处→_→  生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/4744233.html   本文主要内容: GC的概念 GC算法     引用计数法(无法解决循环...

weixin_34109408的博客 435

自建 HTML获取腾讯六宫格点选图片验证码素材,实现刷新批量获取图片方便训练

通过自建 HTML 页面,可以方便地获取腾讯六宫格二维码素材,不仅过程简单,而且可以灵活配置各种参数。希望这篇文章能帮助到需要相关素材的小伙伴。如果你有其他问题或者更好的方法,欢迎留言交流!

代码简单说 Vue、JAVA、PHP、Node.js 熟练运用,接口、架构、性能全搞定。 488

GC 算法详解

1.GC算法是什么 频繁收集Young区; 较少收集Old区; 基本不动Perm区; 2.GC三大算法总体概述 JVM在进行GC时,并非每次都对上面三个内存区域一起回收的,大部分时候回收的都是指新生代,因此GC按照回收的区域又分了两种类型,一种是普通GC(minor GC),一种是全局GC(major GC or Full GC)。 ...

程序员学习圈 1452

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

GC四大算法详解

GC垃圾回收的四大算法详解:复制算法,标记清除算法,标记压缩算法,分代收集算法。参考文章:https://www.jianshu.com/p/9e6841a895b4

AtlantisChina 7175

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

GC垃圾回收介绍及GC算法详解

目录引言GC的作用域什么是垃圾回收?常见的GC算法1.引用计数法2.复制算法3.标记清除4.标记整理小总结5.分代收集算法ps:可达性分析算法?可达性分析的作用可达性分析与垃圾回收算法的关系结论在编程世界中,内存管理是一个至关重要的话题。对于使用自动内存管理的语言(如Java、Python、Go等),垃圾回收(Garbage Collection, GC)机制是确保程序高效运行的关键。本文将介绍垃圾回收的基本概念,并详细讲解四种常见的垃圾回收算法。记住GC口诀: 分代收集算法次数频繁Young区,次数较少O

秃头之旅 1652

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

JAVA GC算法详解

生存还是死亡 对象是否需要被垃圾收集器回收主要有两种方式:引用计数法和可达性分析算法 引用计数法 给对象添加一个引用计数器,每当有一个地方引用他的时候,计数器的数值就+1,当引用失效时,计数器就-1;任何时候计数器的数值都为0的对象时不可能再被使用的。 客观的来说,引用计数法实现简单,判定效率高,但是无法解决对象的循环引用的问题。所以现在的虚拟机很少使用这种算法辣判断对象是否存活。 可达性分析算法...

weixin_30537451的博客 140

【JVM笔记】GC算法详解

目录: 一、如何判断对象(在堆中的实例)可以被回收 1.1引用计数法 1.2可达性分析算法 二、如何判断一个常量是废弃常量 三、如何判断一个类是无用的类 四、垃圾回收算法(GC,Garbage Collection) 4.1标记-清除算法(Mark-Sweep) 4.2复制算法(Copy) 4.3标...

小七的博客 388

对象存活判定算法、GC算法、STW、GC种类详解

对象存活判定算法、GC算法、STW、GC种类详解

安静的软件工程师 1336

java GC收集器详解 GC算法详解

PS: 最近复习GC方面的知识,发现该博客比较不错,收藏一下! 概述 垃圾收集 Garbage Collection 通常被称为“GC”,它诞生于1960年 MIT 的 Lisp 语言,经过半个多世纪,目前已经十分成熟了。 jvm 中,程序计数器、虚拟机栈、本地方法栈都是随线程而生随线程而灭,栈帧随着方法的进入和退出做入栈和出栈操作,实现了自动的内存清理,因此,我们的内存垃圾回收主要集中于 jav...

qq_33779644的博客 552

【GC算法】jvm垃圾收集算法详解

GC算法是作为一个java程序猿所必须了解的东西,不仅在日常生活中有助于我们更深入的理解代码,也是在面试中必定会考的东西。 一:标记-清除算法    标记-清除算法作为最基础的收集算法,其分为“标记”与“清除”两个阶段,当触发GC时,jvm会暂停所有工作,第一阶段阶段会通过标记算法标记出所有需回收的对象,在之后的第二阶段回收所有被标记的对象。    市场上主流的标记算法都是可达性分析算法。这个算法的

silk_bar的专栏 596

【JVM】对象存活判定算法、GC算法、STW、GC种类详解

【JVM】对象存活判定算法、GC算法、STW、GC种类详解

blblccc 2501

GC--算法详解

GC算法概述 JVM进行GC和Full GC时,并非每次都对上面三个内存区域一起回收的,大部分时候回收的都是新生代。因此,GC按照回收的区域又分成了两种类型,一种是普通GC(mimor GC),一种是全局GC(major GC or Full GC)。 minor Gc和Full GC的区别: 普通GC(Minor GC):只针对新生代区域的GC,指发生再新生代的垃圾收集动作,因为大多数Jav...

吴声子夜歌的博客 541

一起学习GC算法(图文详解)

你好我是辰兮,很高兴你能来阅读,本篇整理了GC即垃圾回收算法相关的知识点,希望对你有帮助,分享获取新知,大家一起进步! 文章目录一、文章序言二、GC算法三、拓展小结 一、文章序言 GC(Garbage Collection):JAVA/.NET中的垃圾回收器。Java是由C++发展来的。它摈弃了C++中一些繁琐容易出错的东西。其中有一条就是这个GC。 Java语言的一个显著优点就是引入垃圾回收机制,在一定程度上解决了内存管理的问题。 垃圾回收可以有效的防止内存泄露,有效的使用空闲的内存; 垃圾回收.

末尾卡片和博主交流学习! 6026

什么是GC?GC的算法有哪些?一文详解

什么是GC?GC的算法有哪些?一文详解

casually的博客 713

java gc算法 适用场景_JAVA GC算法详解

生存还是死亡对象是否需要被垃圾收集器回收主要有两种方式:引用计数法和可达性分析算法引用计数法给对象添加一个引用计数器,每当有一个地方引用他的时候,计数器的数值就+1,当引用失效时,计数器就-1;任何时候计数器的数值都为0的对象时不可能再被使用的。客观的来说,引用计数法实现简单,判定效率高,但是无法解决对象的循环引用的问题。所以现在的虚拟机很少使用这种算法辣判断对象是否存活。可达性分析算法基本思路就...

weixin_39630498的博客 258
上一篇: (二)传输协议
下一篇: (七)配置nginx的负载均衡
github_zwl
博客等级 码龄11年 300粉丝 171原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值