Java学习笔记(对象的释放)

对于基本类型变量来说,因为都被分配在内存栈中,因此释放不是问题,而且都会被及时地释放.但对于引用类型来说,就不一样了.
Java提供了基本的对象内存回收机制-垃圾回收器.下面看看如何工作:
首先我们必须了解一点,引用类型的变量和基本类型的变量一样,都是被分配到内存栈里的,只是引用类型的变量在栈中保存的是
一个引用地址(指针),该引用地址所指的堆内存就是实际的对象存放区。
Java的垃圾回收器对于Java程序来说是外部程序,是独立运行的,因此必须有一种机制,让垃圾回收器知道哪些对象(堆中)
是不再被用的,最简单的方法当然是对对象引用计数:
一个对象被一个对象变量引用,其对象引用计数就加1,如果一个对象的引用变量(在栈中)超出生存期,被释放时,对象引用计数
就减1,这样,垃圾回收器就可以根据对象引用计数来判断对象是否可以被收回。看起来这种方法确实比较简单,但实际上,
这种方式还是有很多问题的:
1)如果对象变量都在栈中,上述机制当然没问题。但实际上对象变量可以是另一个对象的成员,而且对象本身也可以包含其它
对象类型的成员变量,这样就会形成一个复杂的引用关系网,这个引用关系网还可能会包含循环引用的情况,就会很容易导致一
些对象在整个程序运行期间都不会被回收,从而产生大量的内存泄露;
2)同步问题。垃圾回收器工作时,如果程序也在工作,也在分配或操作对象,比如一个对象的引用计数虽然为0,垃圾
回收器回收该对象,但同时,这个对象又被引用到一个新的对象变量,就会产生不可预知的错误。为了防止这种冲突,垃圾回
收器工作时程序就必须停止工作。这就会带来另外一个问题,程序运行效率降低。

现在这种利用对象引用计数方式的垃圾回收方式已经很少单独使用。

另外一种方法是采用对象跟踪技术的方法:
垃圾回收器工作时,从程序栈内存中的引用变量开始,遍历对象引用,标记对象可达。那么不可达的对象都可以回收掉。
这种方法解决了循环引用的问题,回收效率比较高,但也同样有以下问题:
1)没有解决垃圾回收器和程序之间的同步问题,垃圾回收器工作期间程序必须停止运行;
2)   每次垃圾回收时,都需要遍历所有的对象,用时会比较长;

当然还有很多垃圾回收策略,大家可以搜一下,虽然垃圾回收对于程序员来说,大部分时间是透明的,但理解这些机制,其实也可以
对我们处理实际问题时提供一种借鉴。
无论是那种回收机制,对于程序员来说,有两个地方是必须关注的:
1)我们的对象什么时候被回收(垃圾回收器运行的不可控);
2)Java产生的对象没问题,但我们自己分配的内存(主要是调用其它语言代码库,比如C++)怎么释放。
       垃圾回收器工作的触发是根据其对内存使用的监控来确定的,当内存空间小于某个阀值时才触发垃圾回收。对于大部分的情况,这应该
不是问题,但如果我们的对象使用了第三方稀缺资源,比如数据库链接,或者我们需要在对象释放的时候做一些清除(比如擦除在界面上的
绘图)工作,我们该怎么办?一种办法当然是主动出击,比如数据库链接,打印机释放等,但有些情况下,我们还是无法主动出击的,比如
一个对象使用了数据库链接,但这个对象被多个其它对象共享,你就很难主动出击释放链接了。对于这种情况,Java提供了另外一种机制,
就是为每个对象提供一个finalize()方法,该方法由垃圾回收器调用(虽然你自己也可以调用,但不建议这样做,原因同无法主动出击类似)。
这样对于对象释放后需要做的清理工作就可以在这个方法中进行。但要注意垃圾回收器对finalize()方法的调用是有限制的,比如每个对象只调用
一次这个方法,因此,我们必须留意对象"复活"所带来的问题。
     对于什么时候我们的对象会被回收的问题,虽然我们可以调用System.gc()来建议(注意,只是建议)垃圾回收器进行回收工作,但实际上
对我们来说,还是不可控的,因此:
1)对于资源,特别是稀缺资源的释放,我们还是应该尽量主动出击来完成;
2)对于调用其它语言代码库,也尽量主动出击进行对象释放,如果不行,至少也要在finalize()方法中完成;

下面的例子,是抄书本上的,用来演示垃圾回收的不确定性(我稍微做了修改):

public class Chair {
	
		static boolean gcrun = false;
		static boolean f = false;
		static int created = 0;
		static int finalized = 0;
		int i;
		Chair() {
		i = ++created;
		if(created == 47)
		System.out.println("Created 47");
		}
		protected void finalize() {
		if(!gcrun) {
		gcrun = true;
		System.out.println(
		"Beginning to finalize after " +
		created + " Chairs have been created=>"+i);
		}
		if(i == 47) {
		System.out.println(
		 "Finalizing Chair #47, " +
		 "Setting flag to stop Chair creation");
		 f = true;
		}
		finalized++;
		if(finalized >= created)
		System.out.println("All " + finalized + " finalized");
		}
}


 

public class GarbageC {
	public static void main(String[] args) {
		
		while(!Chair.f) {
		   new Chair();
		   new String("To take up space");
		}
		System.out.println(
		"After all Chairs have been created:\n" +
		"total created = " + Chair.created +
		", total finalized = " + Chair.finalized);
		String theMethString ="after";
		if(theMethString.equals("before")) {
		 	System.out.println("gc():");
			System.gc();
		 	System.out.println("runFinalization():");
			System.runFinalization();
		}
		System.out.println("bye!");
		if(theMethString.equals("after"))
		  System.runFinalizersOnExit(true);
		}
}



 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值