java存在内存泄漏的问题吗,java内存泄漏的原因及解决办法

  java存在内存泄漏的问题吗,java内存泄漏的原因及解决办法

  

目录

Java内存泄漏:典型内存泄漏摘要

 

  00-1010所谓内存泄漏,是指某个程序不再使用的对象或变量已经被占用在内存中。

  Java中有一个垃圾收集机制,可以保证当一个对象不再被引用时,也就是当该对象成为孤儿时,该对象会被垃圾收集器自动从内存中清除。

  既然java有垃圾收集机制,为什么会有内存泄漏的问题?

  只是有些对象无法被垃圾收集器处理,导致这些对象一直占用JVM内存,会导致内存泄漏。

  由于Java使用有向图进行垃圾收集管理,因此可以消除引用循环的问题。例如,有两个相互引用的对象。只要它们是根进程无法到达的,GC也可以回收它们。例如,下面的代码可以看到这种情况下的内存回收。

  导入java。io。IOException公共类garbage test { public static void main(String[]args)抛出IOException { try { //TODO自动生成的方法存根GC test();} catch(io exception e){ e . printstacktrace();} System.out.println(已退出gcTest!);system . in . read();system . in . read(); out begin gc!);for(int I=0;i 100I){ system . GC();system . in . read();system . in . read();} }私有静态void gcTest()抛出io exception { system . in . read();system . in . read();人员p1=新人员();system . in . read();system . in . read();Person p2=新人();P1 . set mate(p2);p2 . set mate(P1);system . out . println( before exit GC test!);system . in . read();system . in . read();system . GC();System.out.println(exit gctest!);}私有静态类Person { byte[]data=new byte[20000000];Person mate=nullpublic void set mate(Person other){ mate=other;} } } Java :中内存泄漏的情况如果长寿命对象持有对短寿命对象的引用,很可能会发生内存泄漏。尽管不再需要一个短命对象,但它不能被回收,因为一个长命对象持有它的引用。这是Java中内存泄漏的场景。通俗地说,一个程序员可能创建了一个对象。这个对象以后不再被使用,但它总是被引用,即这个对象没有用但不能被垃圾收集器收集。这就是java中可能出现内存泄漏的情况。

  例如,在缓存系统中,我们加载一个对象并将其放在缓存中(例如,放在全局地图对象中),然后我们就再也不会使用它了。该对象的值被缓存引用,但不再随便使用。

  检查Java中的内存泄漏。一定要让程序完全执行各种分支,直到程序结束,然后看有没有对象被使用过。如果不是,可以判断这个对象属于内存泄漏。

  如果外部类的实例对象的方法返回内部类的实例对象,那么内部类对象已经被引用很久了。即使不再使用外部类实例对象,外部类对象也不会被垃圾回收,因为内部类持久化了外部类的实例对象,这也会造成内存泄漏。

  以下内容来自互联网(主要特点是清除堆栈中的一个元素,不是完全从数组中移除,而是减少总存储数。我可以写得比这更好。在移除一个元素时,顺便让它从数组中消失,只需将该元素所在位置的值设置为null)

  我实在想不出比那个栈更经典的例子了,只好引用别人的例子。

  子,下面的例子不是我想到的,是书上看到的 ,当然如果没有在书上看到,可能过一段时间我自己也想的到,可是那时我说是我自己想到的也没有人相信的。

  

public class Stack { private Object[] elements = new Object[10]; private int size = 0; public void push(Object e) { ensureCapacity(); elements[size++] = e; } 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); } }}

上面的原理应该很简单,假如堆钱加了10 个元素 ,然后全部弹出来 ,虽然堆钱是空的,没有我们要的东西,但是这是个对象是无法回收的,这个才符合了内存泄露的两个条件 无用,无法回收。 但是就是存在这样的东西也不一定会导致什么样的后果 ,如果这个堆钱用的比较少,也就浪费了几个 K 内存而己,反正我们 的内存都上 G 了,哪里会有什么影响,再说这个东西很快就会被回收的,有什么关系。 下面看两个例子。

 

  

class Bad { public static Stack s = new Stack(); static { s.push(new Object()); s.pop(); //这里有一个对象发生内存泄露 s.push(new Object());//上面的对象可以被回收了,等于是自愈了 }}

因为是 static ,就一直存在 到程序退出,但是我们也可以看到它有自愈功能,就是说如果你的 Stack 最多有 100 个对象,那么最多也就只有 100 个对象无法 被回收, 其实这个应该很容易理解,Stack 内部持有 100 个引用,最坏的情况就是 他们都是无用的,因为我们一旦放新的进取,以前的引用自然消失!

 

  内存泄露的另外一种情况: 当一个对象被存储进 HashSet 集合中以后,就不能修改这个对象中的那些参与计算哈希值的字段了,否则,对象修改后的晗希值与 最初存储进 HashSet 集合中时的哈希值就不同了,在这种情况下,即使在 contains 方法使用该对象的当前引用作为的参数去 HashSet 集合中检索对象, 也将返回找不到对象的结果,这也会导致无法从 HashSet 集合中单独删除当前对象,造成内存泄露。

  

 

  

附:内存泄露的典型情况

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

 

  

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()方法改成下面的代码就安全多了:

 

  

public Object pop(){ if(element.length==size) throws EmptyStackException(); Object o=element[--size]; elements[size]=null; //使得GC有机会回收这个对象 return o; }

 

  

总结

到此这篇关于Java内存泄露问题的文章就介绍到这了,更多相关Java内存泄露问题内容请搜索盛行IT以前的文章或继续浏览下面的相关文章希望大家以后多多支持盛行IT!

 

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: