当前位置: 主页 > JAVA语言

请简述java的内存回收机制-简述java中异常处理的机制

发布时间:2023-05-22 11:06   浏览次数:次   作者:佚名

1.什么叫内存泄漏?

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

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

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

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

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

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

通过这种有向图的内存管理方式,当一个内存对象失去了所有的引用之后,GC 就可以将其回收。反过来说请简述java的内存回收机制,如果这个对象还存在引用,那么它将不会被 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……

importjava.util.ArrayList;

importjava.util.List;

publicclassMemoryTest{

privatestaticListlist=newArrayList();

privatestaticintcount=0;

publicstaticvoidmain(String[]args)throwsInterruptedException{

System.out.println("申请前的可用内存="+getFreeMemory());

while(true){

list.add(newbyte[1024*1024]);//用实例变量申请1M内存,当方法执行完毕时,这个static的变量是不会被释放

count++;

if(count0==0){

System.out.println("当前list.size()="+list.size()+",可用内存="+getFreeMemory());

Thread.sleep(500);

}

}

}

publicstaticlonggetFreeMemory(){

returnRuntime.getRuntime().freeMemory()/(1024*1024);

}

}

所以我们要慎用类变量。