Java垃圾回收机制

从内存原理 理解java 垃圾回收机制

 

先看一下JVM的内存模型:

 


 

从大的方面来讲,JVM的内存模型分为两大块:

 

永久区内存( Permanent space )和堆内存(heap space)。

 

栈内存(stack space)一般都不归在JVM内存模型中,因为栈内存属于线程级别。

每个线程都有个独立的栈内存空间。

 

Permanent space里存放加载的Class类级对象如class本身,methodfield等等。

heap space主要存放对象实例和数组。

heap spaceOld GenerationNew Generation组成,Old Generation存放生命周期长久的实例对象,而新的对象实例一般放在New Generation

New Generation还可以再分为Eden(圣经中的伊甸园)、和Survivor区,新的对象实例总是首先放在Eden区,Survivor区作为Eden区和Old区的缓冲,可以向Old区转移活动的对象实例。

 

1) 在Young Generation中,有一个叫Eden Space的空间,主要是用来存放新生的对象,还有两个Survivor Spacesfromto),它们的大小总是一样,它们用来存放每次垃圾回收后存活下来的对象。

2) 在Old Generation中,主要存放应用程序中生命周期长的内存对象。

3) 在Young Generation块中,垃圾回收一般用Copying的算法,速度快。每次GC的时候,存活下来的对象首先由Eden拷贝到某个SurvivorSpace,当Survivor Space空间满了后,剩下的live对象就被直接拷贝到OldGeneration中去。因此,每次GC后,Eden内存块会被清空。

4) 在Old Generation块中,垃圾回收一般用mark-compact的算法,速度慢些,但减少内存要求。

5) 垃圾回收分多级,0级为全部(Full)的垃圾回收,会回收OLD段中的垃圾;1级或以上为部分垃圾回收,只会回收Young中的垃圾,内存溢出通常发生于OLD段或Perm段垃圾回收后,仍然无内存空间容纳新的Java对象的情况。

 

Copying算法 将所有需要存活的对象拷贝到一片连续的空闲的内存区中,然后将原内存中的所有对象均清空。优点:拷贝后的对象的内存地址是连续的

Mark-compact算法:整理标记,将所有存活的对象移向一个区域,使其连续,然后将其余的对象清空

Mark-sweeping:清除标记算法

 

System.gc()

(1) GC是垃圾收集的意思(Gabage Collection),内存处理是编程人员容易出现问题的地方,忘记或者错误的内存回收会导致程序或系统的不稳定甚至崩溃,Java提供的GC功能可以自动监测对象是否超过作用域从而达到自动回收内存的目的,Java语言没有提供释放已分配内存的显示操作方法。

 

(2) 对于GC来说,当程序员创建对象时,GC就开始监控这个对象的地址、大小以及使用情况。通常,GC采用有向图的方式记录和管理堆(heap)中的所有对象。通过这种方式确定哪些对象是"可达的",哪些对象是"不可达的"。当GC确定一些对象为"不可达"时,GC就有责任回收这些内存空间。可以。程序员可以手动执行System.gc(),通知GC运行,但是Java语言规范并不保证GC一定会执行。

 

(3) 垃圾回收是一种动态存储管理技术,它自动地释放不再被程序引用的对象,当一个对象不再被引用的时候,按照特定的垃圾收集算法来实现资源自动回收的功能。

 

(4) System.gc();就是呼叫java虚拟机的垃圾回收器运行回收内存的垃圾。

 s

(5) 当不存在对一个对象的引用时,我们就假定不再需要那个对象,那个对象所占有的存储单元可以被收回,可通过System.gc()方法回收,但一般要把不再引用的对象标志为null为佳。

 

(6) 每个 Java 应用程序都有一个 Runtime 类实例,使应用程序能够与其运行的环境相连接。可以通过 getRuntime 方法获取当前运行时。 Runtime.getRuntime().gc();

 

(7) java.lang.System.gc()只是java.lang.Runtime.getRuntime().gc()的简写,两者的行为没有任何不同。

 

(8) 唯一的区别就是System.gc()写起来比Runtime.getRuntime().gc()简单点. 其实基本没什么机会用得到这个命令, 因为这个命令只是建议JVM安排GC运行, 还有可能完全被拒绝。 GC本身是会周期性的自动运行的,由JVM决定运行的时机,而且现在的版本有多种更智能的模式可以选择,还会根据运行的机器自动去做选择,就算真的有性能上的需求,也应该去对GC的运行机制进行微调,而不是通过使用这个命令来实现性能的优化。

 

 

Finalize()

注意:如果你熟悉C++,那你知道C++允许你为一个类定义一个撤消函数(destructor ),它在对象正好出作用域之前被调用。Java不支持这个想法也不提供撤消函数。finalize() 方法只和撤消函数的功能接近。当你对Java 有丰富经验时,你将看到因为Java使用垃圾回收子系统,几乎没有必要使用撤消函数。


finalize的工作原理应该是这样的:一旦垃圾收集器准备好释放对象占用的存储空间,它首先调用finalize(),而且只有在下一次垃圾收集过程中,才会真正回收对象的内存.所以如果使用finalize(),就可以在垃圾收集期间进行一些重要的清除或清扫工作.

finalize()在什么时候被调用?
有三种情况
1.所有对象被Garbage Collection时自动调用,比如运行System.gc()的时候.
2.程序退出时为每个对象调用一次finalize方法。
3.显式的调用finalize方法

除此以外,正常情况下,当某个对象被系统收集为无用信息的时候,finalize()将被自动调用,但是jvm不保证finalize()一定被调用,也就是说,finalize()的调用是不确定的,这也就是为什么sun不提倡使用finalize()的原因

 

 

练习

程序段1:

1.fobj = new Object ( ) ;

2.fobj. Method ( ) ;

3.fobj = new Object ( ) ;

4.fobj. Method ( ) ;

问:这段代码中,第几行的fobj 符合垃圾收集器的收集标准?

答:第3行。因为第3行的fobj被赋了新值,产生了一个新的对象,即换了一块新的内存空间,也相当于为第1行中的fobj赋了null值。这种类型的题在认证0考试中是最简单的。

程序段2:

1.Object sobj = new Object ( ) ;

2.Object sobj = null ;

3.Object sobj = new Object ( ) ;

一起jquery,17jquery

4.sobj = new Object ( ) ;

问:这段代码中,第几行的内存空间符合垃圾收集器的收集标准?

答:第2行和第4行。因为第2行为sobj赋值为null,所以在此第1行的sobj符合垃圾收集器的收集标准。而第4行相当于为sobj赋值为null,所以在此第3行的sobj也符合垃圾收集器的收集标准。

如果有一个对象的句柄a,且你把a作为某个构造器的参数,即 new Constructor ( a )的时候,即使你给a赋值为null,a也不符合垃圾收集器的收集标准。直到由上面构造器构造的新对象被赋空值时,a才可以被垃圾收集器收集。

程序段3:

1.Object aobj = new Object ( ) ;

2.Object bobj = new Object ( ) ;

3.Object cobj = new Object ( ) ;

4.aobj = bobj;

5.aobj = cobj;

6.cobj = null;

7.aobj = null;

问:这段代码中,第几行的内存空间符合垃圾收集器的收集标准?

答:第4,7行。注意这类题型是认证考试中可能遇到的最难题型了。

1-3分别创建了Object类的三个对象:aobj,bobj,cobj

4:此时对象aobj的句柄指向bobj,原来aojb指向的对象已经没有任何引用或变量指向,这时,就符合回收标准。

5:此时对象aobj的句柄指向cobj,所以该行的执行不能使aobj符合垃圾收集器的收集标准。

6:此时仍没有任何一个对象符合垃圾收集器的收集标准。

7:对象cobj符合了垃圾收集器的收集标准,因为cobj的句柄指向单一的地址空间。在第6行的时候,cobj已经被赋值为null,但由cobj同时还指向了aobj(第5行),所以此时cobj并不符合垃圾收集器的收集标准。而在第7行,aobj所指向的地址空间也被赋予了空值null,这就说明了,由cobj所指向的地址空间已经被完全地赋予了空值。所以此时cobj最终符合了垃圾收集器的收集标准。 但对于aobj和bobj,仍然无法判断其是否符合收集标准。

总之,在Java语言中,判断一块内存空间是否符合垃圾收集器收集标准的标准只有两个:

1.给对象赋予了空值null,以下再没有调用过。

2.给对象赋予了新值,既重新分配了内存空间。

最后再次提醒一下,一块内存空间符合了垃圾收集器的收集标准,并不意味着这块内存空间就一定会被垃圾收集器收集。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

finbarr45

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值