Java中典型的内存泄露问题和解决方法

Q:在Java中怎么可以产生内存泄露?
A:Java中,造成内存泄露的原因有很多种。典型的例子是一个没有实现hasCode和
equals方法的Key类在HashMap中保存的情况。最后会生成很多重复的对象。所有的内存泄露
最后都会抛出OutOfMemoryError异常,下面通过一段简短的通过无限循环模拟内存泄露
的例子说明一下。

代码如下:

import java.util.HashMap;
import java.util.Map;

public class MemoryLeak {

public static void main(String[] args) {
  Map<Key, String> map = new HashMap<Key, String>(1000);

int counter = 0;
  while (true) {
       // creates duplicate objects due to bad Key class
   map.put(new Key("dummyKey"), "value");
   counter++;
   if (counter % 1000 == 0) {
    System.out.println("map size: " + map.size());
    System.out.println("Free memory after count " + counter
      + " is " + getFreeMemory() + "MB");

sleep(1000);
   }

}
 }

// inner class key without hashcode() or equals() -- bad implementation
 static class Key {
  private String key;

public Key(String key) {
   this.key = key;
  }

}

//delay for a given period in milli seconds
 public static void sleep(long sleepFor) {
  try {
   Thread.sleep(sleepFor);
  } catch (InterruptedException e) {
   e.printStackTrace();
  }
 }

//get available memory in MB
 public static long getFreeMemory() {
  return Runtime.getRuntime().freeMemory() / (1024 * 1024);
 }

}

结果如下:

代码如下:

map size: 1000
Free memory after count 1000 is 4MB
map size: 2000
Free memory after count 2000 is 4MB
map size: 1396000
Free memory after count 1396000 is 2MB
map size: 1397000
Free memory after count 1397000 is 2MB
map size: 1398000
Free memory after count 1398000 is 2MB
map size: 1399000
Free memory after count 1399000 is 1MB
map size: 1400000
Free memory after count 1400000 is 1MB
map size: 1401000
Free memory after count 1401000 is 1MB
.....
.....
map size: 1452000
Free memory after count 1452000 is 0MB
map size: 1453000
Free memory after count 1453000 is 0MB
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
 at java.util.HashMap.addEntry(HashMap.java:753)
 at java.util.HashMap.put(HashMap.java:385)
 at MemoryLeak.main(MemoryLeak.java:10)

Q:怎么解决上面的内存泄露?
A:实现Key类的equals和hasCode方法。
 

代码如下:

.....
static class Key {
 private String key;

public Key(String key) {
  this.key = key;
 }

@Override
 public boolean equals(Object obj) {

if (obj instanceof Key)
   return key.equals(((Key) obj).key);
  else
   return false;

}

@Override
 public int hashCode() {
  return key.hashCode();
 }
}
.....

重新执行程序会得到如下结果:
 

代码如下:

map size: 1
Free memory after count 1000 is 4MB
map size: 1
Free memory after count 2000 is 4MB
map size: 1
Free memory after count 3000 is 4MB
map size: 1
Free memory after count 4000 is 4MB
...
Free memory after count 73000 is 4MB
map size: 1
Free memory after count 74000 is 4MB
map size: 1
Free memory after count 75000 is 4MB

Q:在实际场景中,你怎么查找内存泄露?
A:通过以下代码获取线程ID

代码如下:

C:\>jps
5808 Jps
4568 MemoryLeak
3860 Main

通过命令行打开jconsole

代码如下:

C:\>jconsole 4568

实现了hasCode和equals的Key类和没有实现的图表如下所示:

没有内存泄露的:

造成内存泄露的:

(0)

相关推荐

  • Java中关于内存泄漏出现的原因汇总及如何避免内存泄漏(超详细版)

    Android 内存泄漏总结 内存管理的目的就是让我们在开发中怎么有效的避免我们的应用出现内存泄漏的问题.内存泄漏大家都不陌生了,简单粗俗的讲,就是该被释放的对象没有释放,一直被某个或某些实例所持有却不再被使用导致 GC 不能回收.最近自己阅读了大量相关的文档资料,打算做个 总结 沉淀下来跟大家一起分享和学习,也给自己一个警示,以后 coding 时怎么避免这些情况,提高应用的体验和质量. 我会从 java 内存泄漏的基础知识开始,并通过具体例子来说明 Android 引起内存泄漏的各种原因,以

  • 详细介绍Java内存泄露原因

    一.Java内存回收机制 不论哪种语言的内存分配方式,都需要返回所分配内存的真实地址,也就是返回一个指针到内存块的首地址.Java中对象是采用new或者反射的方法创建的,这些对象的创建都是在堆(Heap)中分配的,所有对象的回收都是由Java虚拟机通过垃圾回收机制完成的.GC为了能够正确释放对象,会监控每个对象的运行状况,对他们的申请.引用.被引用.赋值等状况进行监控,Java会使用有向图的方法进行管理内存,实时监控对象是否可以达到,如果不可到达,则就将其回收,这样也可以消除引用循环的问题.在J

  • Java内存各部分OOM出现原因及解决方法(必看)

    一,jvm内存区域 1,程序计数器 一块很小的内存空间,作用是当前线程所执行的字节码的行号指示器. 2,java栈 与程序计数器一样,java栈(虚拟机栈)也是线程私有的,其生命周期与线程相同.通常存放基本数据类型,对象引用(一个指向对象起始地址的引用指针或一个代表对象的句柄),reeturnAddress类型(指向一条字节码指令的地址) 栈区域有两种异常类型:如果线程请求的栈深度大于虚拟机所允许的深度,将抛StrackOverflowError异常:如果虚拟机栈可以动态扩展(大部分虚拟机都可动

  • Java常见内存溢出异常分析与解决

    Java虚拟机规范规定JVM的内存分为了好几块,比如堆,栈,程序计数器,方法区等,而Hotspot jvm的实现中,将堆内存分为了三部分,新生代,老年代,持久带,其中持久带实现了规范中规定的方法区,而内存模型中不同的部分都会出现相应的OutOfMemoryError错误,接下来我们就分开来讨论一下.java.lang.OutOfMemoryError这个错误我相信大部分开发人员都有遇到过,产生该错误的原因大都出于以下原因: JVM内存过小.程序不严密,产生了过多的垃圾. 导致OutOfMemor

  • 理解Java中的内存泄露及解决方法示例

    本文详细地介绍了Java内存管理的原理,以及内存泄露产生的原因,同时提供了一些列解决Java内存泄露的方案,希望对各位Java开发者有所帮助. Java内存管理机制 在C++ 语言中,如果需要动态分配一块内存,程序员需要负责这块内存的整个生命周期.从申请分配.到使用.再到最后的释放.这样的过程非常灵活,但是却十分繁琐,程序员很容易由于疏忽而忘记释放内存,从而导致内存的泄露. Java 语言对内存管理做了自己的优化,这就是垃圾回收机制. Java 的几乎所有内存对象都是在堆内存上分配(基本数据类型

  • Java中典型的内存泄露问题和解决方法

    Q:在Java中怎么可以产生内存泄露?A:Java中,造成内存泄露的原因有很多种.典型的例子是一个没有实现hasCode和equals方法的Key类在HashMap中保存的情况.最后会生成很多重复的对象.所有的内存泄露最后都会抛出OutOfMemoryError异常,下面通过一段简短的通过无限循环模拟内存泄露的例子说明一下. 复制代码 代码如下: import java.util.HashMap;import java.util.Map; public class MemoryLeak { pu

  • java中double类型运算结果异常的解决方法

    问题: 对两个double类型的值进行运算,有时会出现结果值异常的问题.比如: System.out.println(19.99+20); System.out.println(1.0-0.66); System.out.println(0.033*100); System.out.println(12.3/100); 输出: 39.989999999999995 0.33999999999999997 3.3000000000000003 0.12300000000000001 解决方法: J

  • Java中URL传中文时乱码的解决方法

    前言 Java中URL传中文时乱码的问题相信不少朋友都遇到过,最近就遇到一个问题,就是在Action当中把一条中文信息绑定在URL的后面,ActionForward到别一个页面时,用reqeust.getParameter取出是出现乱码的问题. 解决办法 1.对要进行URL传递的中文字符进行编码: String message = java.net.URLEncoder.encode("中文字符","utf-8"); 2.在取URL传递中文的页面对字符进行解码: S

  • Java中对List去重 Stream去重的解决方法

    问题 当下互联网技术成熟,越来越多的趋向去中心化.分布式.流计算,使得很多以前在数据库侧做的事情放到了Java端.今天有人问道,如果数据库字段没有索引,那么应该如何根据该字段去重?大家都一致认为用Java来做,但怎么做呢? 解答 忽然想起以前写过list去重的文章,找出来一看.做法就是将list中对象的hashcode和equals方法重写,然后丢到HashSet里,然后取出来.这是最初刚学Java的时候像被字典一样背写出来的答案.就比如面试,面过号称做了3年Java的人,问Set和HashMa

  • Java中的内存泄露问题和解决办法

    目录 为什么会产生内存泄漏? 内存泄漏对程序的影响? 如何检查和分析内存泄漏? 常见的内存泄漏及解决方法 1.单例造成的内存泄漏 2.非静态内部类创建静态实例造成的内存泄漏[已无] 3.Handler造成的内存泄漏 4.线程造成的内存泄漏 5.资源未关闭造成的内存泄漏 6.使用ListView时造成的内存泄漏 7.集合容器中的内存泄露 8.WebView造成的泄露 如何避免内存泄漏? 总结 (Memory Leak,内存泄漏) 为什么会产生内存泄漏? 当一个对象已经不需要再使用本该被回收时,另外

  • 深度理解Java中volatile的内存语义

    volatile可见性实验 举个栗子 我这里开了两个线程,后面的线程去修改volatile变量,前面的线程不断获取volatile变量, 结果是会一致卡在死循环,控制台没有任何输出 假如将flag让volatile来进行修饰 结果是:三秒后,就不会不断打印出信息出来 注意,Thread.sleep是会刷新线程内存的,所以不要使用Thread.sleep来分别让一个线程获取两次volatile变量 volatile的特性 volatile其实相当于对变量的单词读或写操作加了锁.做了同步 由于是加了

  • Java中ThreadLocal 导致内存 OOM 的原因分析

    目录 原因分析 正确的使用方式 原因分析 ThreadLocal 导致内存 OOM 的原因是什么? ThreadLocal 底层通过 ThreadLocalMap 存储数据 源码如下:  当我们使用ThreadLocal.set()时,set的value与key(即业务自己定义的ThreadLocal类)会存储在ThreadLocalMap的Entry[]数组里 源码如下: 其中Entry是实现了一个弱引用WeakReference,Entry的key(即业务方定义的 ThreadLocal类)

  • java OOM内存泄漏原因及解决方法

    前言 这篇文章主要介绍了java OOM内存泄漏原因及解决方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 一.什么是OOM OOM,全称"Out Of Memory",翻译成中文就是"内存用完了",当JVM因为没有足够的内存来为对象分配空间并且垃圾回收器也已经没有空间可回收时,就会抛出这个error 二.为什么会OOM.出现的原因是什么 为什么会没有内存了呢?原因不外乎有两点: ① 分配的少了:比如虚拟机本身可

  • java中同类对象之间的compareTo()和compare()方法对比分析

    首先我们都知道java中的比较都是同一类对象与对象之间的比较,就好像现实生活中比较人和人的年龄一样,你不会去把人的年龄和人的身高来比较,这显然是没有意义的. java中同类对象之间的比较又分为两种,基本类型之间的比较和引用类型之间的比较. java中"=="比较对象是否引用了同一个对象,或者比较基本类型变量值是否相等.Object类的equals()方法用来比较是否一个对象(内存地址比较),可以重写. JDK中有些类重写了equals()方法,只要类型.内容都相同,就认为相等.很变态的

  • 在java中main函数如何调用外部非static方法

    使用外部方法时(不管是static还是非static),都要先new一个对象,才能使用该对象的方法. 举例如下: 测试函数(这是错误的): public class Test { public static void main(String[] args) { Employee employee = null; employee.setName("旺旺"); //有警告,况且这里也执行不下去 employee.setEmail("ww@qq.com"); emplo

随机推荐