Java内存泄漏问题--java既然存在垃圾回收机制,为什么还存在内存泄漏?

1.什么叫内存泄漏?

简单来说就是一个东西放在内存里的时间太长了,当你的程序都跑完了,它还存在那里。这时它是白白的占用了你的内存,累积起来占用的内存越来越多……最后就会导致JVM报错:out of memory。他占用的是我们的物理内存。

2.java内存泄漏的根本原因是?

内存对象明明已经不需要的时候,还仍然保留着这块内存和它的访问方式(引用)。

3.java既然存在gc线程,为什么还存在内存泄漏?

这个问题,我们需要知道 GC 在什么时候回收内存对象,什么样的内存对象会被 GC 认为是“不再使用”的。

Java中对内存对象的访问,使用的是引用的方式。在 Java 代码中我们维护一个内存对象的引用变量,通过这个引用变量的值,我们可以访问到对应的内存地址中的内存对象空间。在 Java 程序中,这个引用变量本身既可以存放堆内存中,又可以放在代码栈的内存中(与基本数据类型相同)。 GC 线程会从代码栈中的引用变量开始跟踪,从而判定哪些内存是正在使用的。如果 GC 线程通过这种方式,无法跟踪到某一块堆内存,那么 GC 就认为这块内存将不再使用了(因为代码中已经无法访问这块内存了)。

通过这种有向图的内存管理方式,当一个内存对象失去了所有的引用之后,GC 就可以将其回收。反过来说,如果这个对象还存在引用,那么它将不会被 GC 回收,哪怕是 Java 虚拟机抛出 OutOfMemoryError 。


例子1:
Vector v = new  Vector( 10 );  
 for  ( int  i = 1 ;i < 100 ; i ++ ){  
 Object o = new  Object();  
 v.add(o);  
 o = null ;  
 }
在这个例子中,代码栈中存在Vector 对象的引用 v 和 Object 对象的引用 o 。
在 For 循环中,我们不断的生成新的对象,然后将其添加到 Vector 对象中,之后将 o 引用置空。问题是当 o 引用被置空后,
如果发生 GC ,
我们创建的 Object 对象是否能够被 GC 回收呢?
答案是否定的。
因为, GC 在跟踪代码栈中的引用时,
会发现 v 引用,而继续往下跟踪,就会发现 v 引用指向的内存空间中又存在指向 Object 对象的引用。也就是说尽管 o 引用已经被置空,
但是 Object 对象仍然存在其他的引用,是可以被访问到的,所以 GC 无法将其释放掉。
如果在此循环之后, Object 对象对程序已经没有任何作用,
那么我们就认为此 Java 程序发生了内存泄漏。

例子2:

如果想要看到内存溢出,可以按这样的思路去尝试一下:定义一个静态的实例变量(list或其它集合),然后在一个方法里循环往这个静态变量塞东西,直到这个实例变量撑爆你的jvm内存。很快你就能看到out of memory……

import  java.util.ArrayList;
import  java.util.List;
 
public  class  MemoryTest {
     private  static  List list =  new  ArrayList();
     private  static  int  count =  0 ;
     
     public  static  void  main(String[] args)  throws  InterruptedException {
         System.out.println( "申请前的可用内存 = " +getFreeMemory());
         while ( true ){
              list.add( new  byte [ 1024 * 1024 ]); //用实例变量申请1M内存,当方法执行完毕时,这个static的变量是不会被释放
              count++;
              if  (count %  100  ==  0 ) {
                  System.out.println( "当前list.size()=" +list.size()+ ",可用内存 = " +getFreeMemory());
                  Thread.sleep( 500 );
              }
         }
     }
     
     public  static  long  getFreeMemory() {
           return  Runtime.getRuntime().freeMemory() / ( 1024  1024 );
          }
 
}

所以我们要慎用类变量。



猜你喜欢

转载自blog.csdn.net/Java_Mrsun/article/details/81019187
今日推荐