分享Java垃圾回收机制学习总结
内存泄漏:内存泄漏是指内存空间使用完毕后未进行回收操作。一般来说,Java中的内存泄漏是因为内存对象生命周期超出其在程序中存在的时间长度
垃圾回收意义:解决编程时需要考虑的内存管理问题,有效解决内存泄漏问题,充分利用空闲内存空间。Java对象不再有作用域的概念,只有对象的引用才具有作用域。
基本操作:(1)发现无用对象;(2)回收无用对象占用的空间,并且释放成程序可以再次使用的空间。
回收时间:垃圾回收具体发生的时间具有不可预知性,大体上说来具有两种时机:
编程人员调用JVM的GC接口,但是仅仅只是告知系统想要进行垃圾回收,具体时间由系统决定;
当程序运行时如果需要大块内存,而此时无法提供足够大的块,则系统会调用GC进行垃圾回收。
回收算法:
引用计数法
内容:每个对象在被创建时,将该对象实例分配给一个变量(称为引用计数器),变量计数初值设为1,当该对象被引用时,计数值加1,当一个对象实例的某个引用超过生命周期或者被设为其他值时,引用计数器减1。当引用计数器值变为0时,可以被当作垃圾回收。(注:该对象实例也可能引用了其他对象,因此当该对象被回收时,它引用的所有对象的计数器都要减1.)
评价:可以较快地执行,在实时系统下比较方便,但是无法解决循环引用问题。例如,对象a和对象b互相引用,但是a和b的值被赋为null,此时a、b引用的对象已经无法被访问,但是它们互相引用,导致其引用计数器的值均不为0,此时GC永远不会回收它们。
根搜索算法
内容:将程序中所有的引用关系当作图,从根节点GC Root对象开始,寻找对应引用的节点,依次类推,所有的引用节点构成一张图,其余的节点则认为是未被引用的节点,即无用节点。
Java中用作GC Root对象的有:Java虚拟机栈中引用的对象、方法区中静态属性引用的对象、方法区中常量引用的对象、本地方法栈中引用的对象
标记-清除算法
内容:从根集合进行扫描,标记存活对象,全部扫描后再扫描未被标记的对象,进行回收。
评价:不需要移动对象,只处理不存活对象,当存活对象较多时比较高效,但是会造成内存碎片。
标记-整理算法
内容:在算法3的基础上,回收完无用对象后,会将所有存活对象向空闲空间移动,整理空闲内存。
评价:开销成本增加,但是解决了碎片化问题。
注:算法3、4、5均属于根搜索算法,此处分开描述是为了便于理解。
copying算法
内容:将内存分为对象区域面和空闲区域面,在对象区进行扫描,然后将对象区的所有有效节点依次copy到空闲区,释放原对象区,此时原对象区变为空闲区。在对象区和空闲区的切换中完成垃圾回收。
评价:减少了句柄的回收,同时不会出现碎片,但是在切换过程中程序需要暂停。
分代算法
用于存放静态文件,如Java类、方法等。持久代对垃圾回收没有显著影响
在年轻代中经历了N次垃圾回收后仍然存活的对象,就会被放到年老代中。因此,可以认为年老代中存放的都是一些生命周期较长的对象。
内存比新生代也大很多(大概比例是1:2),当老年代内存满时触发Major GC即Full GC,Full GC发生频率比较低,老年代对象存活时间比较长,存活率标记高。
所有新生成的对象首先都是放在年轻代的。年轻代的目标就是尽可能快速的收集掉那些生命周期短的对象。
新生代内存按照8:1:1的比例分为一个eden区和两个survivor(survivor0,survivor1)区。一个Eden区,两个 Survivor区(一般而言)。大部分对象在Eden区中生成。回收时先将eden区存活对象复制到一个survivor0区,然后清空eden区,当这个survivor0区也存放满了时,则将eden区和survivor0区存活对象复制到另一个survivor1区,然后清空eden和这个survivor0区,此时survivor0区是空的,然后将survivor0区和survivor1区交换,即保持survivor1区为空, 如此往复。
当survivor1区不足以存放 eden和survivor0的存活对象时,就将存活对象直接存放到老年代。若是老年代也满了就会触发一次Full GC,也就是新生代、老年代都进行回收
新生代发生的GC也叫做Minor GC,MinorGC发生频率比较高(不一定等Eden区满了才触发)
内容:基于不同对象生命周期不一样,将对象分代(共分为三代:新生代、年老代、持久代)处理。
新生代:
年老代:
持久代:
以上就是分享Java垃圾回收机制学习总结的详细内容,更多请关注其它相关文章!