java中是否存在内存泄漏?什么情况下才是内存泄漏?
2019-07-23 18:25
68 查看
版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/MengHen_0_0/article/details/97009448
简介
所谓内存泄露就是指一个不再被程序使用的对象或变量一直被占据在内存中。
内存泄漏的情况:
- java 中的内存泄露的情况:
长生命周期的对象持有短生命周期对象的引用就很可能发生内存泄露,尽管短生命周期对象已经不再需要,但是因为长生命周期对象持有它的引用而导致 不能被回收,这就是 java 中内存泄露的发生场景。
例一: 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); } } }
例二: public class Bad{ public static Stack s=Stack(); static{ s.push(new Object()); s.pop(); //这里有一个对象发生内存泄露 s.push(new Object()); //上面的对象可以被回收了,等于是自愈了 } } }
上面的原理应该很简单,假如堆栈加了10个元素,然后全部弹出来,虽然堆栈是空的, 没有我们要的东西,但是这是个对象是无法回收的,这个才符合了内存泄露的两个条件:无 用,无法回收。
- 内存泄露的另外一种情况:
当一个对象被存储进 HashSet 集合中以后,就不能修改这个对 象中的那些参与计算哈希值的字段了,否则,对象修改后的哈希值与最初存储进 HashSet 集合中时的哈希值就不同了,在这种情况下,即使在 contains 方法使用该对象的当前引用 作为的参数去 HashSet 集合中检索对象,也将返回找不到对象的结果,这也会导致无法从 HashSet 集合中单独删除当前对象,造成内存泄露。
import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Map; public class MemoryLeak { @SuppressWarnings({ "unchecked", "rawtypes"}) public static void main(String[] args) { Collection coll = new HashSet(); Map map1 = new HashMap(); Map map2 = new HashMap(); map1.put(3, 3); map2.put(5, 5); coll.add(map1); coll.add(map2); System.out.println("未修改的map1的hashCode:"+map1.hashCode()); System.out.println("未移除map1之后的coll的长度:"+coll.size()); System.out.println(coll.toString()); map1.put(3,7); coll.remove(map1); System.out.println("修改后的map1的hashCode:"+map1.hashCode()); System.out.println("移除map1之后的coll的长度:"+coll.size()); System.out.println(coll.toString()); }
对于已经加入HashSet的对象,如果修改参与计算HashCode的属性的信息,会导致删除该HashSet中的该对象无效,从而导致内存泄漏。
java中对内存泄漏的应对机制:
java中有垃圾回收机制,它可以保证一对象不再被引用的时候,即对象编程了孤儿的时候,对象将自动 被垃圾回收器从内存中清除掉。由于 Java 使用有向图的方式进行垃圾回收管理,可以消除 引用循环的问题,例如有两个对象,相互引用,只要它们和根进程不可达的,那么 GC 也是 可以回收它们的,例如下面的代码可以看到这种情况的内存回收:
import java.io.IOException; publicclass GarbageTest { public static voidmain(String[] args)throws IOException { try { gcTest(); } catch (IOException e) { e.printStackTrace(); } System.out.println("hasexited gcTest!"); System.in.read(); System.in.read(); System.out.println("out begingc!"); for(int i=0;i<100;i++){ System.gc(); System.in.read(); System.in.read(); } } private static voidgcTest()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); p2.setMate(p1); System.out.println("beforeexit gctest!"); System.in.read(); System.in.read(); System.gc(); System.out.println("exitgctest!"); } private static classPerson{ byte[] data =new byte[20000000]; Person mate = null; public void setMate(Personother){ mate = other; } } }
避免内存泄漏的方法:
- 程序进行字符串处理时,尽量避免使用String,而应使用StringBuffer。
- 尽量少用静态变量。
- 避免集中创建对象尤其是大对象,如果可以的话尽量使用流操作。
- 尽量运用对象池技术以提高系统性能。
- 不要在经常调用的方法中创建对象,尤其是忌讳在循环中创建对象。
- 尽早释放无用对象的引用。
相关文章推荐
- Java内存机制和是否会有内存泄漏什么情况下会泄漏
- java中是否存在内存泄漏,内存泄漏出现在那些情况中
- "每日一道面试题".net托管堆是否会存在内存泄漏的情况
- java是否存在内存泄漏
- 内存监控方法之——Jmap结合Memory Analyzer,分析java程序是否存在内存泄漏
- [华为面试题_ND2]运行错误请检查是否存在数组越界非法访问_野指针乱访问_空指针乱访问等情况_java_scanner_error
- Java语言中是否存在内存泄漏的问题
- 什么情况下Java对象才是已经死亡?
- java中是否会存在内存泄漏
- JAVA中是否存在内存泄漏
- 什么情况下Java对象才是已经死亡?
- 在什么情况下Java比C++快
- java中会存在内存泄漏吗
- java 多种判断key是否在map中存在的方法
- JAVA文本操作处理 完成一个java application应用程序,判别指定路径下指定文件名的文件是否存在
- java判断String字符串数组中是否存在某个值
- 用Java语句判断数据库表是否存在
- JAVA之旅(二十八)——File概述,创建,删除,判断文件存在,创建文件夹,判断是否为文件/文件夹,获取信息,文件列表,文件过滤
- static关键字是什么意思?java中是否可以覆盖一个private方法或者static方法
- Java 判断多级路径是否存在,不存在就创建