【JVM学习笔记】垃圾回收基础篇

今年就要去参加面试了,之前读完了《深入理解JAVA虚拟机》这本书,感觉并没有完全参透,现在重读这本书,希望能得到不一样的收获。

 

目录

Stop-The-World介绍

对象的年龄(垃圾分代)

垃圾回收的常用算法

1:引用计数法(Java虚拟机并没有采用这种方式)

2:标记-清除法 

3:标记-整理算法(也称作标记-压缩算法)

4:复制算法 

5.分代收集算法


Java和C++一个重要的区别是:需不需要考虑内存回收。

C++内存的分配和释放都需要靠程序员手动实现,而Java程序员只需分配资源,而不需要手动释放资源。这样虽然减轻了程序员的负担,但是相应的,软件系统也受到了同等的威胁。如果在任务结束或失败时,没有及时的释放资源或释放不完全,就会造成内存泄漏,严重时会造成内存泄漏。因此程序员虽然不需要手动释放资源,但必须知道内存回收的内部细节,这样就在发生内存泄漏时才能够准确的找出问题的所在。

Stop-The-World介绍

垃圾回收是一种极其耗费资源的操作,此时cpu负载会增大,而且如果GC时继续运行程序,那么对象关系就在不断的变化中,对可回收对象的分析就会无法保证准确性,所以应用程序将会挂起除了GC线程以外的所有线程,直至GC完成。这个停止的过程被称为“stop-the-world”。依照实际情况,以调整垃圾回收算法、更改虚拟机参数等方式减少stop-the-world的占用时间,就是一种内存调优的常用方式。

对象的年龄(垃圾分代)

为什么要分代?

有些对象需要频繁的创建,但是存活时间不长,有些对象仅创建一次,但存活时间却很长,那么对于这两种对象就要选择不用的GC策略以减少stop-the-world时间,提高程序的流畅性。那么要怎样区别这些对象的?没错,就是对象分代。新创建的对象被归为新生代,持续几次没有被回收的的对象被归为老年代,而静态文件,Java类与方法这种一般不会被回收或回收价值不大的对象就被分到了永久代(永久代并不是一定不发生GC)。

垃圾回收的常用算法

1:引用计数法(Java虚拟机并没有采用这种方式)

原理:每使用一个对象时就给该对象的引用计数器+1,引用失效时就给引用计数器-1,当对象的引用数量为0时,就说明该对象未被使用

缺点:不能处理循环引用问题,两个对象相互引用,当两个对象都使用完毕时,由于两个垃圾对象都持有对对方的引用,导致两个对象都无法被回收。

2:标记-清除法 

从GC根节点(GC Root)开始标记所有引用该节点及其子节点的对象,标记完毕后,回收所有未被标记的对象。

Java中可作为GC Root的对象有

 1、虚拟机栈中引用的对象

2、方法区中静态属性和常量引用的对象

3、本地方法栈中JNI(native方法)引用的对象 

  

示意图:

【JVM学习笔记】垃圾回收基础篇_第1张图片

缺点:1:需要回收的对象位置随机,回收后会造成大量的内存碎片,在堆空间的分配过程中,大对象的内存分配效率下降。

2:标记和清除的效率都不高。

【JVM学习笔记】垃圾回收基础篇_第2张图片

3:标记-整理算法(也称作标记-压缩算法)

标记-整理算法其实是标记-清除算法的升级,它克服标记-清除算法的内存碎片问题,当然,它也付出了相应的代价,而代价就是“copy”。

【JVM学习笔记】垃圾回收基础篇_第3张图片

4:复制算法 

 

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

由实际检测证明两块内存不需要1:1,因为新生代的98%对象都是“朝生夕死”的,所以虚拟机一般都采用两块Survivor区和一块Eden区。具体操作为:将Eden和Survivor的存活对象保存到另一个Survivor区内,清除Eden和Survivor区的所有对象。

【JVM学习笔记】垃圾回收基础篇_第4张图片

5:分代收集算法

根据各种年龄代的特征不同而衍生出的算法。

比如:

  • 新生代每次GC会有大量对象死去,只有少部分被留下,所以采用复制算法
  • 老年代存活时间长,且没有额外的控件对它进行分配担保,所以采用“标记-清除”或“标记-整理”算法。

你可能感兴趣的:(Java)