Java虚拟机使用引用计数来确定对象是否存活?

Java的内存管理并不单纯依赖引用计数来决定对象是否存活。虽然引用计数在某些场景下有效,但在处理相互引用的对象时会失效,导致内存泄漏。实际运行中,Java的垃圾收集器(GC)采用更复杂的策略,能够处理这种相互引用的情况,确保正确回收不再使用的对象,即使在对象引用计数不为0时也能进行有效的内存管理。
摘要由CSDN通过智能技术生成

很多人都认为Java的内存管理机制使用的是引用计数这样的方式来确定一个对象是否存活:大致意思就是,为每个对象设定一个引用计数,当该对象被引用则该计数+1,解除引用的时候该计数-1,则当计数为0时则该对象即可被释放,否则认为该对象不能被清理。

然而,遇到这样的问题又会怎么样呢?

/**
*	Using java -Xmx8M -Xms8m OutOfMemory
*	to run this demo
*/
class OutOfMemory{

	private static int SIZE_1MB = 1024*1024;

	private byte[] data = new byte[SIZE_1MB];

	public static void main(String args[]){

		int i;
		Object objs[] = new Object[100];
		for(i=0;i<100;i++){
			objs[i] = new OutOfMemory();
		}
	}
}

通过为java命令设定参数,设定堆大小为8m,那么,很明显,这个程序会因为内存不足而挂掉。

这便是Java堆中内存不足,而现有的对象均不可被GC清理(因为每个对象实例的引用都还没解除,也就是引用计数不为0),故因内存不足而死掉。

而如果把程序改成这样:

/**
*	Using java -Xmx8M -Xms8m OutOfMemory2
*	to run this demo
*/
class OutOfMemory2{

	private static int SIZE_1MB = 1024*1024;

	private byte[] data = new byte[SIZE_1MB];

	public static void main(String args[]){

		int i;
		Object obj;
		for(i=0;i<100;i++){
			obj = new OutOfMemory();
		}
	}
}


程序并不会因内存不足而挂掉,究其原因,在每次调用new之后,把新的对象的引用赋值给obj,则上一次new产生的对象便失去引用,该对象便可视为“垃圾”,GC便会在需要的时候对其进行清理,因而不会出现内存不足的问题。

而遇到这样一个程序 的时候,情况就不一样了:

/**
 * @author hackeris
 *  Using java -Xmx8M -Xms8m IsGCUsingReferenceCounting
 *	to run this demo
 */
public class IsGCUsingReferenceCounting {

    public Object referenceOfAnotherObject = null;

    private static final int SIZE_1MB = 1024 * 1024;

    private byte[] data = new byte[SIZE_1MB];

    public static void main(String args[]) {

        int i;
        for (i = 0; i < 100; i++) {

            testGC();
//            System.gc();
        }
    }

    public static void testGC() {

        IsGCUsingReferenceCounting obj1 = new IsGCUsingReferenceCounting();
        IsGCUsingReferenceCounting obj2 = new IsGCUsingReferenceCounting();
        obj1.referenceOfAnotherObject = obj2;
        obj2.referenceOfAnotherObject = obj1;
    }
}


如果GC是通过引用计数来确定对象是否存活,那么这个程序就无法正常的结束,必然会因为内存不足而挂掉。在testGC函数中,obj1持有obj2的引用,obj2持有obj1的引用,因此两个对象的引用计数均不为0,故在函数testGC退出的时候,它们由于相互引用,其引用计数均不会减少,那么这样的情况下,GC便无法将其清理,使得最终程序会因为内存不足而挂掉。

但我们实际运行这个程序的时候却一切风平浪静,GC能够应对这样的相互引用的情况,可以看出,GC并非使用单纯的引用计数来确定一个对象是否存活,而是采用了更加高明的策略。


笔者使用的Java环境如下:


java version "1.7.0_51"
Java(TM) SE Runtime Environment (build 1.7.0_51-b13)
Java HotSpot(TM) 64-Bit Server VM (build 24.51-b03, mixed mode)


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值