请问JAVA里面存在内存泄露问题吗? 请问JAVA里面存在内存泄露问题吗?今天面试的题目,看到这个问题我晕了!如果有泄露的情况,也就是说GC做的不好!到底是怎么回事情,最后有代码说服我! 解决方案 » 免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货 据说是有的,上次在校内bbs上看到有人提起,可以google看看 按Java的理论是应该不存在的但是java编译器是用什么编的?它有没有呀?这就得问问有研究的人了 java的自动单元收集避免了内存丢失等动态内存分配导致的问题,java也不支持指针,这杜绝了内存的非法访问。 其实,是存在内存泄露的http://blog.csdn.net/hbcui1984/archive/2006/11/07/1370785.aspx 当然存在effective java中还举了例子 我认为,如果简单说“Java 存在内存泄漏问题”,那是在有意或无意地混淆视听。首先要明确什么是“内存泄漏”。恐怕大多数人的概念里,“内存泄漏”指的是 C/C++ 里那种“分配了一块内存,用完后没有释放,也不再有指针指向这块内存”。程序执行到这,后面的程序再没有任何办法使用这块内存,却也永远无法释放它(除非程序终止)。可以肯定地说,Java 中是不会出现上面这种情况的!所谓“Java 的内存泄漏问题”,其实指的是另一种完全不同的情况,即所谓的“无意识保留”。也就是说,当程序执行到某处时,某个对象从程序逻辑上已经不再需要了,但从程序语法上却还保留着(被某个变量所引用),造成 GC 无法对其进行回收。这种所谓的“泄漏”,其危害程度相对比较小,而且往往能够“自愈”。我们讨论“Java 是否存在内存泄漏问题”的时候,不要停留在得到一个“存在”或者“不存在”的结论,而是要搞清楚它的实际含义,这样才能真正对我们的软件开发工作有所助益。 maquan说的很专业啊。Java程序内存泄漏都是指应用程序编写不当,造成无法内存对象无法回收造成的,和Java本身没有关系,和开发者有关。现在推荐使用Java 6.0的ref API,SoftReference, WeakReference & PhantaomReference能帮助开发者减少内存泄漏的现象。详细可以看Java的Document。另外NetBeans和Profiler也可以帮你检测程序是否有内存泄漏问题,在哪儿出现的等等。 我个人认为:java是会存在内存泄露的。垃圾回收机制是回收长时间不用的内存块,如果你有一个对象长时间没有使用,被GC回收了,如果这时候有一个引用指向了这个对象,不就发生了内存泄露了吗? 是的,存在这样的问题。maquan说的很对 这个问题怎么说呢 大家都知道内存泄漏指用了内存后没有释放。但是这个释放的动作是谁触发的呢?当然是写程序的人。难道你在c++中显式的释放一个对象的时候,c++会不给你释放?所以说内存泄漏是由人决定的而不是某种语言。c++和java的一个区别就是c++需要显式的释放对象,而java是由gc来完成的。对于程序员来说前者可能会麻烦一点,但是他的效率也好于后者。不过对目前的硬件环境而言这点效率好像已经不算什么了。java的gc只是回收不再用的对象。最后一句话 内存泄漏是由人决定的而不是某种语言 存在啊,有一种情况就是使用Java的本地方法调用,这时候调用一些c语言写的方法或程序,而这些程序存在内存泄露。两一种情况就是网上举的例子,用java模拟一个堆栈,在出栈的时候的一些失误引起的。 存在, 如: int i,j; i=i+j; 当i和j都足够大的时候。 这要看内存泄漏的定义了。举例来说,内存泄漏可能会有一种比较典型的定义,就是当一个程序退出时,是否有未归还给操作系统的内存。(假设操作系统自己不会自动收回)。对于这种情况,如果有的话,那是Java虚拟机的问题。另外楼上的那个叫溢出,不叫内存泄漏。 maquan说的极是,讨论这个议题之前我们首先要明确什么是“内存泄漏”,否则鸡同鸭讲. 如果你写一个死循环不断的new 不同的对象,最后JVM抛出out of memory,然后说:看,这不就是java内存泄漏了吗? 那我没话说了. 另外,这也不是投票, 只说存在还是不存在是没啥意义的.java的这个“内存泄漏”话题已经被说的很玄乎,但我觉得程序员嘛,靠山吃山,最好用实际程序说明问题.一段被流传很广的如下代码(参考上面某楼的链接http://blog.csdn.net/hbcui1984/archive/2006/11/07/1370785.aspx)Vector v=new Vector(10);for (int i=1;i<100; i++){ Object o=new Object(); v.add(o); o=null; }说是加上o=null;gc会回收对象占用的内存,提高内存使用率,实际上是脱裤子放屁. 运行以下一段代码就会明白,注释或者不注释//mybyteOBJ=null;结果应该是一样的,不要告诉我System.gc();不一定总是有效之类的话,也许应该另开一个Thread讨论System.gc();的问题:) Thread.currentThread().setPriority(Thread.MIN_PRIORITY); long total = 0; Vector vt = new Vector(); System.gc(); long oldmem = getFreeMem(); for (int i = 0; i < 1000; i++) { Integer mybyteOBJ=new Integer(i); vt.add(mybyteOBJ); //mybyteOBJ=null; System.gc(); total = total + (oldmem - getFreeMem()); } System.out.println("total=" + total); private long getFreeMem() { long mem = Runtime.getRuntime().freeMemory(); return mem; } 事实上java内存分配远没想象的那么简单,例如上面的代码,往vector加Object,内存消耗也不是增加一倍(或者以上),而是远远小于一倍,到此我猜你也许想说点什么,欢迎继续:)还有其他例子,不一一列出了. 但无论是啥情况,JVM都可以很好的进行内存回收.那种所谓"即使每次运行少量泄漏,长期运行之后,系统也是面临崩溃的危险。"是荒谬的,除非你的代码错误,否则JVM会在崩溃之前很好的回收内存(很难想象有人会把JVM配置成"长期运行之后"再进行gc) vector加Object时只是添加Object的地址,并不是Object的所有内存,内存当然不会成倍的增加了Object是new 时分配的地址及内存. maquan('ma:kju) ( ) 信誉:100 Blog 2006-11-23 11:37:36 得分: 0 我认为,如果简单说“Java 存在内存泄漏问题”,那是在有意或无意地混淆视听。首先要明确什么是“内存泄漏”。恐怕大多数人的概念里,“内存泄漏”指的是 C/C++ 里那种“分配了一块内存,用完后没有释放,也不再有指针指向这块内存”。程序执行到这,后面的程序再没有任何办法使用这块内存,却也永远无法释放它(除非程序终止)。可以肯定地说,Java 中是不会出现上面这种情况的!所谓“Java 的内存泄漏问题”,其实指的是另一种完全不同的情况,即所谓的“无意识保留”。也就是说,当程序执行到某处时,某个对象从程序逻辑上已经不再需要了,但从程序语法上却还保留着(被某个变量所引用),造成 GC 无法对其进行回收。这种所谓的“泄漏”,其危害程度相对比较小,而且往往能够“自愈”。我们讨论“Java 是否存在内存泄漏问题”的时候,不要停留在得到一个“存在”或者“不存在”的结论,而是要搞清楚它的实际含义,这样才能真正对我们的软件开发工作有所助益。 ===================================================================大致同意,但是实际上C/C++那种类型的内存泄漏,在JAVA中同样存在,你说的后者是开发人员造成的泄漏,前者是虚拟机内部的内存泄漏,这个在使用JNI的时候比较多。 严格来说,我想绝对没有人百分之百相信JVM在任何情况下都不会发生内存泄漏现象,不可能做到如此完美。 好了好了, 都别争了, java 是最完美的语言, 绝对不出任何的错误,行了吧 一直以为java不存在memory leak......看了maquan的文章弄清楚,多谢maquan. 已经猜到有人会说:vector加Object时只是添加Object的地址...仔细再看看就可以明白,当接下来加上mybyteOBJ=null;后,vector里头mybyteOBJ就再也不能只是地址引用了,无论如何必须有其他地方的内存存放mybyteOBJ.这也是为什么说加上mybyteOBJ=null;是多此一举.事实也是如此.我的观点还是只管写好你自己程序,不用操心JVM的所谓"内存泄漏".倒是有其他几种情况值得讨论.1.程序访问JVM之外的资源,例如文件系统,看以下一段程序 writeFileTest(); System.gc(); System.out.println("test ok"); private void writeFileTest() { try { FileOutputStream fs=new FileOutputStream("D:/youtest.log", true); Writer fw =new OutputStreamWriter(fs); fw.write("this is a test"); fw.flush(); } catch (Exception ex) { ex.printStackTrace(); } }在System.gc();设个断点,然后debug运行程序,按道理writeFileTest()方法结束,那么它方法内的变量也随之销毁,释放资源.但实际上如果在运行System.gc()之前用写字版(一定用这个程序)打开的话,它会提示文件正被另外的程序使用...这是因为上面的程序在writeFileTest()里头没有调用fs.close()显式的关闭资源. 但是在同一个JVM里头,当你再次访问youtest.log时,JVM知道该怎么做,不会让你对"方法结束,变量销毁"感到失望,但对JVM之外的程序,例如上面的写字板则是另外一回事,所以对类似的第三方资源,应该显示的调用close()之类的方法显式的关闭资源,而不应该依赖gc. 幸运的是java对类似的资源都有类似close的方法,你只要照着做,gc的事让JVM来吧.2.非简单new 出来的变量资源, 最典型的是JDBC 连接池获得的Connection. private void ConnTest(){ Connection conn=pool.getConn(); ..... conn=null;}你不能指望ConnTest()方法结束,里头的conn变量销毁, 因为你不是简单的new 出来,而是从pool里头获得引用,方法结束,pool并没有结束,而且你不知道pool如何对待你的引用,所以加上conn=null也未必有用.以上这些不应该跟java "内存泄漏"扯上关系,而是活生生的程序错误.另外,楼上的可真会掰:) 我可以不长篇大论么?我可以copy别人的长篇大论么?我可以不自以为是么?首先请某些同学购买或下载《effective java》来看,谢谢。以下是第二章:创建和销毁对象http://www.matrix.org.cn/resource/upload/forum/2005_12_13_182559_zJoNyezkbm.pdf请找到 第5条:消除过期的对象引用 “当你从一种手工管理内存的语言(比如C或C + +)转换到一种具有垃圾回收功能的语言的时候,你作为一个程序员,工作会变得更加容易,因为当你用完了对象之后,它们会被自动回收。当你第一次经历对象回收功能的时候,你会觉得这有点不可思议。这很容易会让你留下这样的印象,认为自己不再需要考虑内存管理的事情了。实际上,这是不正确的。............ 在支持垃圾回收的语言中,内存泄漏是很隐蔽的(这样的内存泄漏被称为“无意识的对象保持(unintentional object retention)”更为恰当)。如果一个对象引用被无意识地保留起来了,那么,垃圾回收机制不仅不会处理这个对象,而且也不会处理被这个对象引用的所有其他对象。即使只有少量的几个对象引用被无意识地保留下来,也会有很多的对象被排除在垃圾回收机制之外,从而对性能造成潜在的重大影响。要想修复这一类问题也很简单:一旦对象引用已经过期,只需清空这些引用即可。在上述例子的Stack类中,只要一个单元被弹出栈,指向它的引用就过期了。pop方法的修订版本如下所示:public Object pop() {if (size==0) throw new EmptyStackException(); Object result = elements[--size]; elements[size] = null; // Eliminate obsolete reference return result;}清空过期引用的另一个好处是,如果它们在以后又被错误地解除引用,则程序会立即抛出NullPointerException异常,而不是悄悄地错误运行下去。尽可能早地检测出程序中的错误总是有益的。”==================================请不要认为获得2002年图灵大奖的图书中存在你能找到的错误,如果你能,那你也不在CSDN发帖子了。 一场看得人郁闷的辩论战,也是所谓最无聊的“定义战”。大家不如先明确讨论下“内存泄漏”的定义吧……楼上所说的还是上前面早有人提到的“无意识的对象保留”?都多了那么多帖了还没搞清楚吗?另外,个人认为,native代码里面的内在泄漏是JVM以外的事吧?要不要算到“Java内存泄漏”里面还有待讨论……不过还好,有不少代码看,这点喜欢,也更能说清问题。^_^ 个人认为System.gc()适用的范围只是在,密码 、加密算法值密私等重要的保密信息吧。让其在不被使用后,马上让垃圾机制回收清零。win2K就存在这样一个问题。可以通过黑客程序在admin login后从内存中取得密码(当然2000是C++写的,这里提到这点只是以为说明一点问题)。 汗,看到标题的第一反映是:该如何才能写出让内存泄露的Java代码呢? http://en.wikipedia.org/wiki/Memory_Leak Effective Java里面的条款5,消除过期的对象引用 public class Stack { private Object[] elements; private int size = 0; public Stack(int initialCapacity){ this.elements = new Object[initialCapacity]; } public void push(Object e){ ensureCapacity(); elements[size++] = s; } public Object pop(){ if(size == 0) throw new EmptyStackException(); return elements[--size]; } private void ensureCapacity(){ if(elements.length == size){ Object[] oldElements = elements; elements = new Object[2 * elements.length + 1]; System.arraycopy(oldElements,0,elements,0,size); } }}这个程序里面就存在着一个“内存泄露”问题,如果这个栈先增长,再收缩,那么,从这个栈中间弹出来的东西将不会被当作垃圾回收,即使使用栈的客户程序不再引用这些对象了,这是因为栈内部维护这些对象的过期引用解决方法,修正pop方法 public Object pop(){ if(size == 0) throw new EmptyStackException(); Object result = elements[--size]; elements[size] = null; return result;} 当然有! 1,java的GC只释放你不再指向的对象。如果一些对象你不再使用了,但仍然有指针指向它,那么就不会释放。如List中的元素。 如果不释放的对象足够多,那么内存就会泄露。 2,Java的GC只释放对象。如果你的Java程序使用了其他资源,而你不手工释放,那么就会发生内存泄露。如,操作系统资源:文件。文件打开后,不关闭,就会造成操作系统问题。还有,操作系统的图形资源。如果不释放,也会发生操作系统问题。另外,还有数据库连接,也会发生内存泄露。 某大侠曰:在Java中,内存泄漏就是存在一些被分配的对象,这些对象有下面两个特点,首先,这些对象是可达的,即在有向图中, 存在通路可以与其相连;其次,这些对象是无用的,即程序以后不会再使用这些对象。如果对象满足这两个条件,这些对象就可以判定为Java中的内存泄漏,这 些对象不会被GC所回收,然而它却占用内存。-------------可见他所谓的java的内存泄漏跟c里面的是两回事,c中的泄漏的内存是不可达的,也就是没有指针指向这个内存区域,而java里面是有指针指向这个区域,只是他对于你的程序来说是没有用的,这是所谓的java的内存泄漏问题。比如:程序定义了也 static map 用来做对象的缓存,但是对象没用后并没有把它清除调,而再map中还有他的引用,当然垃圾回收是不会回收这个内存的。 呵呵,小弟就是上面那篇链接(http://blog.csdn.net/hbcui1984/archive/2006/11/07/1370785.aspx)的博主,没想到这几天针对这个问题讨论如此热烈,大家的热情小弟敬佩!首先要说明的是,本篇文章我是从IBM developerworks转载过来,虽然对文章中某些内容不敢苟同,但是我不能修改人家的文章,就以原版内容拷了过来。下面再聊聊下面这段代码:Vector v=new Vector(10);for (int i=1;i<100; i++){Object o=new Object();v.add(o);o=null;}这段代码,被认为是经典的内存泄漏的代码,其实,本人感觉并无内存泄漏,以下是我的几点看法:1.o=null; 对这句代码,我的看法和大多数达人的看法是一致的,即:o是一个局部变量,在超出其作用域时,自动取消对Object的引用,因此,这行代码是没有必要的。2.对于v,只要程序中还在使用该Vector,则v就不会释放其引用,并且new出来的100个Object也不会释放其相应的内存,只有当v不再被引用或者超出其作用域时,v的引用才会被取消,这时,new出来的100个Object才可能被释放。3.对于new出来的Object,我个人认为只有v对它们有引用关系,o对他们的引用关系在跳出循环之后自动取消了。4.为了在是jvm尽快释放不需要的内存,在程序中,程序员可以显式的使用v=null来取消v的引用,这样,容器和其中的对象所占用的内存都可以被释放。5.也许可以换种思路理解作者的含义,也许,作者想告诉我们的意思是:虽然是用了o=null,但是并没有释放Object所占用的内存,只有在该Object所在的容器也消亡时,该Object才会释放相应的内存,而要尽早使没用的Object消亡,可以显示的指定v=null;以上是我个人的看法,欢迎大家批评指正。 建议某些同学copy东西也应该copy全点, 还是用程序说明问题用-Xms1m -Xmx1m JVM参数运行以下YourTest程序, JVM将抛出out of memory错误,于是....那个Stack(WrongStack)没有错误吗? 一个实现堆栈数据结构的程序,东西出栈了,堆栈里还保留着这个东西而不清空没有错误(bug)么? 自己程序写错了硬要说是java "内存泄漏"是不厚道的.其实下面的这个程序把WrongStack ws=new WrongStack(1);注释掉,换成RightStack ws = new RightStack(1); 加大i的循环次数甚至死循环,很明显JVM还将抛出out of memory错误, 这下不会再说java "内存泄漏"了吧如果隐蔽的程序错误叫"内存泄漏",明显的程序错误叫"程序错误",那又算是哪门逻辑呢?import java.util.Vector;import java.util.Date;import java.util.EmptyStackException;public class YourTest { Vector vt = new Vector(); public YourTest() { for (int i = 0; i < 1000; i++) { WrongStack ws=new WrongStack(1); //RightStack ws = new RightStack(1); for (int j = 0; j < 100; j++) { ws.push(new Date()); } for (int j = 0; j < 100; j++) { ws.pop(); } vt.add(ws); } System.out.println("test ok"); } public static void main(String[] args) { YourTest yourTest1 = new YourTest(); } class WrongStack { private Object[] elements; private int size = 0; public WrongStack(int initialCapacity) { this.elements = new Object[initialCapacity]; } public void push(Object e) { ensureCapacity(); elements[size++] = e; } public Object pop() { if (size == 0) { throw new EmptyStackException(); } return elements[--size]; } /** * ensureCapacity */ private void ensureCapacity() { if (elements.length == size) { Object[] oldElements = elements; elements = new Object[2 * elements.length + 1]; System.arraycopy(oldElements, 0, elements, 0, size); } } } class RightStack { private Object[] elements; private int size = 0; public RightStack(int initialCapacity) { this.elements = new Object[initialCapacity]; } public void push(Object e) { ensureCapacity(); elements[size++] = e; } public Object pop() { if (size == 0) throw new EmptyStackException(); Object result = elements[--size]; elements[size] = null; // Eliminate obsolete reference return result; } /** * ensureCapacity */ private void ensureCapacity() { if (elements.length == size) { Object[] oldElements = elements; elements = new Object[2 * elements.length + 1]; System.arraycopy(oldElements, 0, elements, 0, size); } } }} stevez() 说得不错不错有些偏执了按照你对“内存泄漏”的理解,不管是那个语言(C,C++,还是Java)都不会存在内存泄漏的问题,只是程序员犯的错误而已呵呵 刚笔试完的题目 求解:Arrays类的反排序问题! 如何使用Eclipse里面的Debug呢? 桌面程序用什么数据库好 昨天看的一个ITMM写的扫雷游戏,稍微改了一下 请教一个java socket问题 tomcat启动不了,高手求救 数组比较问题 到底该不该初始化变量,怎么出使化? 为什么我的RMI远程对象死活band不上去?? 总结帖:去掉集合中重复的自定义类项 新手求教
http://blog.csdn.net/hbcui1984/archive/2006/11/07/1370785.aspx
effective java中还举了例子
Java程序内存泄漏都是指应用程序编写不当,造成无法内存对象无法回收造成的,和Java本身没有关系,和开发者有关。
现在推荐使用Java 6.0的ref API,SoftReference, WeakReference & PhantaomReference能帮助开发者减少内存泄漏的现象。详细可以看Java的Document。
另外NetBeans和Profiler也可以帮你检测程序是否有内存泄漏问题,在哪儿出现的等等。
大家都知道内存泄漏指用了内存后没有释放。但是这个释放的动作是谁触发的呢?当然是写程序的人。难道你在c++中显式的释放一个对象的时候,c++会不给你释放?所以说内存泄漏是由人决定的而不是某种语言。
c++和java的一个区别就是c++需要显式的释放对象,而java是由gc来完成的。对于程序员来说前者可能会麻烦一点,但是他的效率也好于后者。不过对目前的硬件环境而言这点效率好像已经不算什么了。java的gc只是回收不再用的对象。
最后一句话 内存泄漏是由人决定的而不是某种语言
另外楼上的那个叫溢出,不叫内存泄漏。
java的这个“内存泄漏”话题已经被说的很玄乎,但我觉得程序员嘛,靠山吃山,最好用实际程序说明问题.
一段被流传很广的如下代码(参考上面某楼的链接http://blog.csdn.net/hbcui1984/archive/2006/11/07/1370785.aspx)Vector v=new Vector(10);
for (int i=1;i<100; i++)
{
Object o=new Object();
v.add(o);
o=null;
}
说是加上o=null;gc会回收对象占用的内存,提高内存使用率,实际上是脱裤子放屁.
运行以下一段代码就会明白,注释或者不注释//mybyteOBJ=null;结果应该是一样的,
不要告诉我System.gc();不一定总是有效之类的话,也许应该另开一个Thread讨论System.gc();的问题:)
Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
long total = 0;
Vector vt = new Vector();
System.gc();
long oldmem = getFreeMem();
for (int i = 0; i < 1000; i++) {
Integer mybyteOBJ=new Integer(i);
vt.add(mybyteOBJ);
//mybyteOBJ=null;
System.gc();
total = total + (oldmem - getFreeMem());
}
System.out.println("total=" + total);
private long getFreeMem() {
long mem = Runtime.getRuntime().freeMemory();
return mem;
}
事实上java内存分配远没想象的那么简单,例如上面的代码,往vector加Object,内存消耗也不是增加一倍(或者以上),而是远远小于一倍,到此我猜你也许想说点什么,欢迎继续:)还有其他例子,不一一列出了.
但无论是啥情况,JVM都可以很好的进行内存回收.那种所谓"即使每次运行少量泄漏,长期运行之后,系统也是面临崩溃的危险。"是荒谬的,除非你的代码错误,否则JVM会在崩溃之前很好的回收内存(很难想象有人会把JVM配置成"长期运行之后"再进行gc)
我认为,如果简单说“Java 存在内存泄漏问题”,那是在有意或无意地混淆视听。首先要明确什么是“内存泄漏”。恐怕大多数人的概念里,“内存泄漏”指的是 C/C++ 里那种“分配了一块内存,用完后没有释放,也不再有指针指向这块内存”。程序执行到这,后面的程序再没有任何办法使用这块内存,却也永远无法释放它(除非程序终止)。可以肯定地说,Java 中是不会出现上面这种情况的!所谓“Java 的内存泄漏问题”,其实指的是另一种完全不同的情况,即所谓的“无意识保留”。也就是说,当程序执行到某处时,某个对象从程序逻辑上已经不再需要了,但从程序语法上却还保留着(被某个变量所引用),造成 GC 无法对其进行回收。这种所谓的“泄漏”,其危害程度相对比较小,而且往往能够“自愈”。我们讨论“Java 是否存在内存泄漏问题”的时候,不要停留在得到一个“存在”或者“不存在”的结论,而是要搞清楚它的实际含义,这样才能真正对我们的软件开发工作有所助益。
===================================================================大致同意,但是实际上C/C++那种类型的内存泄漏,在JAVA中同样存在,你说的后者是开发人员造成的泄漏,前者是虚拟机内部的内存泄漏,这个在使用JNI的时候比较多。
我的观点还是只管写好你自己程序,不用操心JVM的所谓"内存泄漏".
倒是有其他几种情况值得讨论.
1.程序访问JVM之外的资源,例如文件系统,看以下一段程序
writeFileTest();
System.gc();
System.out.println("test ok");
private void writeFileTest() {
try {
FileOutputStream fs=new FileOutputStream("D:/youtest.log", true);
Writer fw =new OutputStreamWriter(fs);
fw.write("this is a test");
fw.flush();
}
catch (Exception ex) {
ex.printStackTrace();
}
}
在System.gc();设个断点,然后debug运行程序,按道理writeFileTest()方法结束,那么它方法内的变量也随之销毁,释放资源.但实际上如果在运行System.gc()之前用写字版(一定用这个程序)打开的话,它会提示文件正被另外的程序使用...
这是因为上面的程序在writeFileTest()里头没有调用fs.close()显式的关闭资源. 但是在同一个JVM里头,当你再次访问youtest.log时,JVM知道该怎么做,不会让你对"方法结束,变量销毁"感到失望,但对JVM之外的程序,例如上面的写字板则是另外一回事,
所以对类似的第三方资源,应该显示的调用close()之类的方法显式的关闭资源,而不应该依赖gc. 幸运的是java对类似的资源都有类似close的方法,你只要照着做,gc的事让JVM来吧.
2.非简单new 出来的变量资源, 最典型的是JDBC 连接池获得的Connection.
private void ConnTest(){
Connection conn=pool.getConn();
.....
conn=null;
}
你不能指望ConnTest()方法结束,里头的conn变量销毁, 因为你不是简单的new 出来,而是从pool里头获得引用,方法结束,pool并没有结束,而且你不知道pool如何对待你的引用,所以加上conn=null也未必有用.
以上这些不应该跟java "内存泄漏"扯上关系,而是活生生的程序错误.
另外,楼上的可真会掰:)
首先请某些同学购买或下载《effective java》来看,谢谢。
以下是第二章:创建和销毁对象http://www.matrix.org.cn/resource/upload/forum/2005_12_13_182559_zJoNyezkbm.pdf
请找到 第5条:消除过期的对象引用
“当你从一种手工管理内存的语言(比如C或C + +)转换到一种具有垃圾回收功能的语言的
时候,你作为一个程序员,工作会变得更加容易,因为当你用完了对象之后,它们会被自动
回收。当你第一次经历对象回收功能的时候,你会觉得这有点不可思议。这很容易会让你留
下这样的印象,认为自己不再需要考虑内存管理的事情了。实际上,这是不正确的。
......
......
在支持垃圾回收的语言中,内存泄漏是很隐蔽的(这样的内存泄漏被称为“无意识的对象
保持(unintentional object retention)”更为恰当)。如果一个对象引用被无意识地保留起来了,
那么,垃圾回收机制不仅不会处理这个对象,而且也不会处理被这个对象引用的所有其他对
象。即使只有少量的几个对象引用被无意识地保留下来,也会有很多的对象被排除在垃圾回
收机制之外,从而对性能造成潜在的重大影响。
要想修复这一类问题也很简单:一旦对象引用已经过期,只需清空这些引用即可。在上述
例子的Stack类中,只要一个单元被弹出栈,指向它的引用就过期了。pop方法的修订版本
如下所示:
public Object pop() {
if (size==0)
throw new EmptyStackException();
Object result = elements[--size];
elements[size] = null; // Eliminate obsolete reference
return result;
}清空过期引用的另一个好处是,如果它们在以后又被错误地解除引用,则程序会立即抛出
NullPointerException异常,而不是悄悄地错误运行下去。尽可能早地检测出程序中的
错误总是有益的。”==================================
请不要认为获得2002年图灵大奖的图书中存在你能找到的错误,如果你能,那你也不在CSDN发帖子了。
都多了那么多帖了还没搞清楚吗?另外,个人认为,native代码里面的内在泄漏是JVM以外的事吧?
要不要算到“Java内存泄漏”里面还有待讨论……不过还好,有不少代码看,这点喜欢,也更能说清问题。^_^
public class Stack {
private Object[] elements;
private int size = 0; public Stack(int initialCapacity){
this.elements = new Object[initialCapacity];
} public void push(Object e){
ensureCapacity();
elements[size++] = s;
} public Object pop(){
if(size == 0)
throw new EmptyStackException();
return elements[--size];
} private void ensureCapacity(){
if(elements.length == size){
Object[] oldElements = elements;
elements = new Object[2 * elements.length + 1];
System.arraycopy(oldElements,0,elements,0,size);
}
}
}这个程序里面就存在着一个“内存泄露”问题,如果这个栈先增长,再收缩,那么,从这个栈中间弹出来的东西将不会被当作垃圾回收,即使使用栈的客户程序不再引用这些对象了,这是因为栈内部维护这些对象的过期引用
解决方法,修正pop方法
public Object pop(){
if(size == 0)
throw new EmptyStackException();
Object result = elements[--size];
elements[size] = null;
return result;
}
1,java的GC只释放你不再指向的对象。如果一些对象你不再使用了,但仍然有指针指向它,那么就不会释放。如List中的元素。 如果不释放的对象足够多,那么内存就会泄露。
2,Java的GC只释放对象。如果你的Java程序使用了其他资源,而你不手工释放,那么就会发生内存泄露。如,操作系统资源:文件。文件打开后,不关闭,就会造成操作系统问题。还有,操作系统的图形资源。如果不释放,也会发生操作系统问题。另外,还有数据库连接,也会发生内存泄露。
在Java中,内存泄漏
就是存在一些被分配的对象,这些对象有下面两个特点,首先,这些对象是可达的,即在有向图中, 存在通路可以与其相连;其次,这些对象是无用的,即程序以后不会再使用这些对象。如果对象满足这两个条件,这些对象就可以判定为Java中的内存泄漏,这 些对象不会被GC所回收,然而它却占用内存。
-------------
可见他所谓的java的内存泄漏跟c里面的是两回事,c中的泄漏的内存是不可达的,也就是没有指针指向这个内存区域,而java里面是有指针指向这个区域,只是他对于你的程序来说是没有用的,这是所谓的java的内存泄漏问题。
比如:程序定义了也 static map 用来做对象的缓存,但是对象没用后并没有把它清除调,而再map中还有他的引用,当然垃圾回收是不会回收这个内存的。
Vector v=new Vector(10);
for (int i=1;i<100; i++){
Object o=new Object();
v.add(o);
o=null;
}
这段代码,被认为是经典的内存泄漏的代码,其实,本人感觉并无内存泄漏,以下是我的几点看法:
1.o=null; 对这句代码,我的看法和大多数达人的看法是一致的,即:o是一个局部变量,在超出其作用域时,自动取消对Object的引用,因此,这行代码是没有必要的。
2.对于v,只要程序中还在使用该Vector,则v就不会释放其引用,并且new出来的100个Object也不会释放其相应的内存,只有当v不再被引用或者超出其作用域时,v的引用才会被取消,这时,new出来的100个Object才可能被释放。
3.对于new出来的Object,我个人认为只有v对它们有引用关系,o对他们的引用关系在跳出循环之后自动取消了。
4.为了在是jvm尽快释放不需要的内存,在程序中,程序员可以显式的使用v=null来取消v的引用,这样,容器和其中的对象所占用的内存都可以被释放。
5.也许可以换种思路理解作者的含义,也许,作者想告诉我们的意思是:虽然是用了o=null,但是并没有释放Object所占用的内存,只有在该Object所在的容器也消亡时,该Object才会释放相应的内存,而要尽早使没用的Object消亡,可以显示的指定v=null;以上是我个人的看法,欢迎大家批评指正。
用-Xms1m -Xmx1m JVM参数运行以下YourTest程序, JVM将抛出out of memory错误,于是....
那个Stack(WrongStack)没有错误吗? 一个实现堆栈数据结构的程序,东西出栈了,堆栈里还保留着这个东西而不清空没有错误(bug)么? 自己程序写错了硬要说是java "内存泄漏"是不厚道的.
其实下面的这个程序把WrongStack ws=new WrongStack(1);注释掉,换成RightStack ws = new RightStack(1); 加大i的循环次数甚至死循环,很明显JVM还将抛出out of memory错误, 这下不会再说java "内存泄漏"了吧
如果隐蔽的程序错误叫"内存泄漏",明显的程序错误叫"程序错误",那又算是哪门逻辑呢?import java.util.Vector;
import java.util.Date;
import java.util.EmptyStackException;public class YourTest {
Vector vt = new Vector();
public YourTest() {
for (int i = 0; i < 1000; i++) {
WrongStack ws=new WrongStack(1);
//RightStack ws = new RightStack(1);
for (int j = 0; j < 100; j++) {
ws.push(new Date());
}
for (int j = 0; j < 100; j++) {
ws.pop();
}
vt.add(ws);
}
System.out.println("test ok");
} public static void main(String[] args) {
YourTest yourTest1 = new YourTest();
} class WrongStack {
private Object[] elements;
private int size = 0;
public WrongStack(int initialCapacity) {
this.elements = new Object[initialCapacity];
} public void push(Object e) {
ensureCapacity();
elements[size++] = e;
} public Object pop() {
if (size == 0) {
throw new EmptyStackException();
}
return elements[--size];
} /**
* ensureCapacity
*/
private void ensureCapacity() {
if (elements.length == size) {
Object[] oldElements = elements;
elements = new Object[2 * elements.length + 1];
System.arraycopy(oldElements, 0, elements, 0, size);
}
}
} class RightStack {
private Object[] elements;
private int size = 0;
public RightStack(int initialCapacity) {
this.elements = new Object[initialCapacity];
} public void push(Object e) {
ensureCapacity();
elements[size++] = e;
} public Object pop() {
if (size == 0)
throw new EmptyStackException();
Object result = elements[--size];
elements[size] = null; // Eliminate obsolete reference
return result;
} /**
* ensureCapacity
*/
private void ensureCapacity() {
if (elements.length == size) {
Object[] oldElements = elements;
elements = new Object[2 * elements.length + 1];
System.arraycopy(oldElements, 0, elements, 0, size);
}
}
}}
stevez() 说得不错不错有些偏执了按照你对“内存泄漏”的理解,不管是那个语言(C,C++,还是Java)都不会存在内存泄漏的问题,只是程序员犯的错误而已呵呵