1、何为内存泄漏
申请了内存用完了不释放
当一个对象是否被使用,当现在不需要。还一直存在。
即:对象不会再被程序用到了。但是GC又不能回收他们的情况,才叫内存泄漏
如果对象的生命周期过长也会出现内存泄漏(OOM)
占着茅坑不拉shi
2、内存溢出
申请内存时,没有足够的内存可以使用
当内存线漏增多,最终会导出内存溢出
3、内存泄漏的8种情况
3.1、静态集合类
public class demo1 {
static List list=new ArrayList();
public void oomTests(){
Object obj=new Object();
list.add(obj);
}
}
3.2、单例模式
单例模式生命周期和JVM一样长,如果持用外包对象的引用,那么这个外部对象也不会被回收,那么就会造成内存泄露
3.3、内部类持有外部类
内部类持有外部类,如果一个外部类的实例对象的方法返回一个内部类的实例对象,
这个内部类对象被长期引用了,即使那个外部类实例对象不再被使用,单由于内部类持有
外部类的实例对象,这个外部类对象不会被垃圾回收,这也会造成内存泄漏
3.4、各种连接,如数据库连接,网络连接和IO连接等
建立连接后需要释放连接
3.5、变量不合理的作用域
一个变量的定义的作用范围大于其使用范围,很有可能会造成内存泄漏。另外一方面,如果没有及时地把对象设置为null,很有可能导致内存线漏
public class demo2 {
private String msg;
public void receiveMsg(){
readFromNet();//从网络中接受数据保存到msg中
saveDB();//把msg保存到数据库中
}
}
3.6、改变哈希值
改变哈希值,当一个对象被存储进HashSet集合中以后,就不能修改这个对象中那些参与计算哈希值的字段了,否则,对象修改后的哈希值与最初存储进行HashSet集合中时的哈希值就不同了
这种情况下,即使在contains方法使用该对象的当前引用作为的参数去HashSet中集合中检索对象,也将返回找不到对象的结果。这也会导致无法从HashSet集合中单独删除当前对象,造成内存泄露
public class ChangeHashCode1 {
public static void main(String[] args) {
HashSet<Point> hs = new HashSet<Point>();
Point cc = new Point();
cc.setX(10);//hashCode = 41
hs.add(cc);
cc.setX(20);//hashCode = 51 此行为导致了内存的泄漏
System.out.println("hs.remove = " + hs.remove(cc));//false
hs.add(cc);
System.out.println("hs.size = " + hs.size());//size = 2
System.out.println(hs);
}
}
class Point {
int x;
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + x;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null) return false;
if (getClass() != obj.getClass()) return false;
Point other = (Point) obj;
if (x != other.x) return false;
return true;
}
@Override
public String toString() {
return "Point{" +
"x=" + x +
'}';
}
}
3.7、缓存泄露
public class MapTest {
static Map wMap = new WeakHashMap();
static Map map = new HashMap();
public static void main(String[] args) {
init();
testWeakHashMap();
testHashMap();
}
public static void init() {
String ref1 = new String("obejct1");
String ref2 = new String("obejct2");
String ref3 = new String("obejct3");
String ref4 = new String("obejct4");
wMap.put(ref1, "cacheObject1");
wMap.put(ref2, "cacheObject2");
map.put(ref3, "cacheObject3");
map.put(ref4, "cacheObject4");
System.out.println("String引用ref1,ref2,ref3,ref4 消失");
}
public static void testWeakHashMap() {
System.out.println("WeakHashMap GC之前");
for (Object o : wMap.entrySet()) {
System.out.println(o);
}
try {
System.gc();
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("WeakHashMap GC之后");
for (Object o : wMap.entrySet()) {
System.out.println(o);
}
}
public static void testHashMap() {
System.out.println("HashMap GC之前");
for (Object o : map.entrySet()) {
System.out.println(o);
}
try {
System.gc();
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("HashMap GC之后");
for (Object o : map.entrySet()) {
System.out.println(o);
}
}
}
3.8、监听器和回调
如果客户端在你实现API中注册回调,却没有显示取消,那么就会积聚。
需要确保回调立即被当做垃圾回收的最佳方法是只保存它的弱引用,例如将他们保存成为
WeakHashMap中的键
总结:
集合,数组,如果进行增删改。操作不正确。是的引用集合的指针操作不当,会存在内存泄露