Java内存泄露问题

 

Java内存泄露问题

内存泄露

所谓内存泄露就是指一个不再被程序使用的对象或变量一直被占据在内存中。 java中有垃圾回收机制,它可以保证一对象不再被引用的时候,即对象编程了孤儿的时候,对象将自动被垃圾回收器从内存中清除掉。由于Java 使用有向图的方式进行垃圾回收管理,可以消除引用循环的问题,例如有两个对象,相互引用,只要它们和根进程不可达的,那么GC也是可以回收它们的,例如下面的代码可以看到这种情况的内存回收:

Java代码 复制代码 收藏代码
  1. public class GarbageTest {
  2. public static void main(String[] args) throws IOException {
  3. try {
  4. gcTest();
  5. } catch (IOException e) {
  6. e.printStackTrace();
  7. }
  8. System.out.println("has exited gcTest!");
  9. System.in.read();
  10. System.in.read();
  11. System.out.println("out begin gc!");
  12. for(int i=0;i<100;i++)
  13. {
  14. System.gc();
  15. System.in.read();
  16. System.in.read();
  17. }
  18. }
  19. private static void gcTest() throws IOException {
  20. System.in.read();
  21. System.in.read();
  22. Person p1 = new Person();
  23. System.in.read();
  24. System.in.read();
  25. Person p2 = new Person();
  26. p1.setMate(p2); //p1中包含p2的引用
  27. p2.setMate(p1); //p2中包含p1的引用
  28. System.out.println("before exit gctest!");
  29. System.in.read();
  30. System.in.read();
  31. System.gc();
  32. System.out.println("exit gctest!");
  33. }
  34. private static class Person
  35. {
  36. byte[] data = new byte[20000000];
  37. Person mate = null;
  38. public void setMate(Person other)
  39. {
  40. mate = other;
  41. }
  42. }
  43. }
public class GarbageTest {

	public static void main(String[] args) throws IOException {
		try {
			gcTest();
		} catch (IOException e) {
			e.printStackTrace();
		}
		System.out.println("has exited gcTest!");
		System.in.read();
		System.in.read();		
		System.out.println("out begin gc!");		
		for(int i=0;i<100;i++)
		{
			System.gc();
			System.in.read();	
			System.in.read();	
		}
	}

	private static void gcTest() throws IOException {
		System.in.read();
		System.in.read();		
		Person p1 = new Person();
		System.in.read();
		System.in.read();		
		Person p2 = new Person();
		p1.setMate(p2); //p1中包含p2的引用
		p2.setMate(p1); //p2中包含p1的引用
		System.out.println("before exit gctest!");
		System.in.read();
		System.in.read();		
		System.gc();
		System.out.println("exit gctest!");
	}

	private static class Person
	{
		byte[] data = new byte[20000000];
		Person mate = null;
		public void setMate(Person other)
		{
			mate = other;
		}
	}
}

当gcTest()方法运行完毕以后,p1和p2对象都变成了垃圾,他们都不会被根对象所找到。关于根对象请参见《JVM垃圾回收机制总结(2) :基本算法概述 》中的关于“垃圾回收从哪里开始”的讨论。

Java的内存泄露

虽然Java的垃圾回收机制较大程度的降低了内存泄露的可能性,但Java程序员仍然可能会写出发生内存泄露的代码。其原因就是一个已经不被使用的短寿命对象被一个长寿命对象(如类的静态成员对象)引用,这就使得本来要被回收的短寿命对象永远无法被回收,造成内存泄露。

内存泄露的典型情况

(1) 数据结构造成的短暂内存泄露问题,看下面的代码

Java代码 复制代码 收藏代码
  1. public class Stack{
  2. private Object[] element=new Object[10];
  3. private int size=0;
  4. public void push(Object ele){
  5. ensureCapacity();
  6. element[size++]=ele;
  7. }
  8. public Object pop(){
  9. if(size==0) throw new EmptyStackException();
  10. return element[--size]; //短暂造成内存泄露
  11. }
  12. private void ensureCapacity(){
  13. if(element.length==size){
  14. Object[] oldElement=element;
  15. element=new Object[size*2+1];
  16. System.arraycopy(oldElement,0,element,0,size);
  17. }
  18. }
  19. }
public class Stack{
      private Object[] element=new Object[10];
      private int size=0;
      
      public void push(Object ele){
             ensureCapacity();
             element[size++]=ele;
      }

      public Object pop(){
             if(size==0) throw new EmptyStackException();
             return element[--size]; //短暂造成内存泄露
      }

      private void ensureCapacity(){
             if(element.length==size){
                     Object[] oldElement=element;
                     element=new Object[size*2+1];
                     System.arraycopy(oldElement,0,element,0,size);
             }
      }
}

上面的代码每一次pop()的时候,Stack都会弹出一个元素,在没有加入新元素之前,实际上仍然有一个引用element[x]指向了这个已经弹出的对象,因此GC是不会对其进行垃圾回收的。只有push()新元素的时候使得element[x]=newObject,才会使得以前创建的对象有可能被回收。应该把上面的pop()方法改成下面的代码就安全多了:

Java代码 复制代码 收藏代码
  1. public Object pop(){
  2. if(element.length==size) throws EmptyStackException();
  3. Object o=element[--size];
  4. elements[size]=null; //使得GC有机会回收这个对象
  5. return o;
  6. }
public Object pop(){
       if(element.length==size) throws EmptyStackException();
       Object o=element[--size];
       elements[size]=null;  //使得GC有机会回收这个对象
       return o;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值