在Java中,程序员不需要去关心内存动态分配和垃圾回收的问题,这一切都交给了JVM来处理。
什么是垃圾?
垃圾是指该对象没有被其他对象引用,那么该对象就是垃圾。所谓使用中的对象(已引用对象),指的是程序中有指针指向的对象;而未使用中的对象(未引用对象),则没有被任何指针给指向,因此占用的内存也可以被回收掉。
主要步骤:标记垃圾,清除(回收)垃圾
标记垃圾
标记垃圾的算法主要有两种, 引用计数法和可达性分析算法
引用算法:给对象添加一个引用计数器,每当有引用它,计数器就加 1;当引用失效,计数器就减 1;当计数器为 0 的对象就是不可能再被使用的,可以当做垃圾收集。
可达性分析算法:上述引用算法有一个缺点,当两个对象相互引用的时候,上述算法会造成内存泄漏,所以有了可达性算法。现存在一个名为GC Roots的对象作为起始点,当该对象到GC Roots没有引用链则说明未被引用,被标记为垃圾。(从离散数学中引入)
清除(回收)垃圾
回收垃圾的条件:
1会在cpu空闲的时候自动进行回收
2在堆内存存储满了之后
3主动调用System.gc()后尝试进行回收
如何回收垃圾:
这里存在着四种垃圾回收算法,标记清除算法、复制算法、标记整理算法以及分代回收算法。
1、标记清除算法
最基础的一种算法,第一个步骤就是标记,第二步将标记的回收。
缺点:效率低,空间浪费(内存碎片)
2、复制算法
通俗的讲就是把内存分为A,B两块,A作为使用,B当作备胎。当A的内存使用完后,把A上未被使用的复制到B上,然后一次性清除A。
缺点: 没有了内存碎片,但是内存少了一半。
3、标记整理算法
比第一种标记清除算法多了整理。
4、分代回收算法(现在使用较多)
分代回收比较智能,体现在他可以根据不同场景选择上述三种不同的回收算法,达到高效。
如何确定场景?
根据对象的生命周期,jvm把内存分为三个区域:新生代,老年代,永久代。
新生代存放生命周期短的,老年代存放生命周期较长的,而永久代(jdk1.8之后更新没有永久代)存放静态文件。
如何选择回收算法?
在新生代中,每次垃圾收集时都发现有大批对象死去,只有少量存活,那就选用复制算法。只需要付出少量存活对象的复制成本就可以完成收集。
老年代中因为对象存活率高、没有额外空间对他进行分配担保,就必须用标记-清除或者标记-整理。
网友评论