垃圾回收的概念
Java的堆是一个运行时的数据区,对象从中分配空间。JVM的堆中存储着正在运行的应用程序
所建立的所有的对象.一般来说他们是不需要程序员显示的进行释放的。堆是由垃圾回收来负责的.
垃圾回收是一种动态的存储管理技术,它自动的释放不在被程序引用的对象的内存空间。并且按照
特定的垃圾收集算法实现资源的自动回收的功能.
垃圾回收的实际意义
我们知道在Java中,当没有对象引用指向原来分配给某个对象的内存地址时,该内存就成为了
一种“孤立”的状态成为垃圾.JVM会自动的释放该内存块(至于什么时候释放,jvm自己才知道)。这意味
着程序不再需要的对象是“无用的信息”,这些信息可以也应该被抛弃,将内存空间让给新的对象使
用。
其实,JVM同时还进行内存碎片的整理,通过对内存块之间的空闲块进行整理,提高了内存的
使用率。垃圾回收的这种释放无用内存空间的做法,减轻了编程的负担,提高了编程的效率,同时
保证了程序的完整性。
不过这回出现一个潜在的缺点:就是程序的开销会加大,性能会受影响。因为jvm必须实时的
跟踪程序中的对象的实时状态,释放掉无用的内存。这同样需要占用处理器的时间。
既然知道了垃圾回收的概念以及时间意义,那就有必要了解垃圾回收的算法实现。
垃圾回收算法分析
概念
通过上面概念性的描述,可以知道的是:JVM垃圾回收一般要做的基本的两件事为:
1、鉴定无用的信息对象
2、回收被无用对象占用的内存空间(并不是回收的对象)
Java语言中并没有明确的说明JVM使用的是那种垃圾回收算法,不过大多数算法都使用了root
set(根集)概念:所谓根集就是正在执行的程序可以访问引用变量的集合(局部变量,参数
类变量),而且程序可以使用引用变量访问对象的属性和方法。垃圾回收首先判断哪些是可达
的(活动对象),哪些是不可达的(“死”的对象)。不可达的对象所占用的内存空间将被回收。
具体有哪些算法呢?简单介绍一下:
1、引用计数法(Reference Counting Collector)
从名字可以看出来,该算法使用计数器来区分活动与非活动对象。可以判断的是堆中分配
的每一个对象都有一个对应的counter,当第一次创建一个对象并赋给一个变量的时候counter为1
若有一个新的变量指向该地址空间,那么counter-1;当变量不在指向该地址空间的时候counter
-1。一旦其counter为0则判定为非活动对象,可回收。(什么时候回收不定)。
可以看出的是这种算法通过维护计数器,垃圾收集器运行较快,但是额外增加了程序的开销
也就是counter的开销。它并未使用根集。无法处理循环引用指向的情况
2、标记--清除器(Tracing Collector)
它使用的是tracing算法,此算法使用了根集的概念,基于此算法的垃圾收集器从根集开始
扫描,识别出可达对象和不可达对象,并且标记可达对象,清除不可达对象。
3、标记--压缩收集器(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算法的垃圾收集器就
是监控当前堆的使用情况,并将选择适当算法的垃圾收集器。
关于垃圾回收的几点补充
(1)垃圾收集发生的不可预知性:
(2)垃圾收集的精确性:主要包括2 个方面:
(a)垃圾收集器能够精确标记活着的对象;
(b)垃圾收集器能够精确地定位对象之间的引用关系。
(3)现在有许多种不同的垃圾收集器,每种有其算法且其表现各异。
(4)垃圾收集的实现和具体的JVM 以及JVM的内存模型有非常紧密的关系。
(5)随着技术的发展,现代垃圾收集技术提供许多可选的垃圾收集器。
关于提高程序性能的思考(由垃圾回收得出的)
1、不要显示调用System.gc
其可以显示的通知JVM进行一次垃圾回收,但是具体执行时间不定!
2、减少使用临时变量
这样就减少了垃圾收集器判定可达对象与不可达对象的开销。
3、对象不用时只为null(对象的引用)
这样同样例如垃圾回收器的判断。
4、尽量使用StringBuffer,减少String的使用
垃圾回收器需要判定的对象减少了
5、尽量使用基本数据类型
6、分散对象的创建或销毁时间
对象的创建或销毁过于集中的话,内存变动太大,jvm会进行一些内存碎片的整理
提高了开销
Tips:还需要指明一点的是,垃圾回收回收的是无用对象的内存空间!回收对象根本就是
离谱的说法!