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

 更新时间:2014年04月28日 08:37:04   作者:  
这篇文章主要介绍了Java中典型的内存泄露问题和解决方法,典型的内存泄露例子是一个没有实现hasCode和 equals方法的Key类在HashMap中保存的情况,可以通过实现Key类的equals和hasCode方法解决这种内存泄漏问题,需要的朋友可以参考下

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类和没有实现的图表如下所示:

没有内存泄露的:

造成内存泄露的:



相关文章

  • mybatis多数据源动态切换的完整步骤

    mybatis多数据源动态切换的完整步骤

    这篇文章主要给大家介绍了关于mybatis多数据源动态切换的完整步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-11-11
  • SpringSecurity根据自定义异常返回登录错误提示信息(账户锁定)

    SpringSecurity根据自定义异常返回登录错误提示信息(账户锁定)

    本文介绍了在SpringSecurity中根据自定义异常返回登录错误提示信息的方法,特别是在账户锁定时,通过记录输错次数、重写校验方法并抛出自定义异常,感兴趣的可以了解一下
    2025-01-01
  • SpringMVC和Spring的配置文件扫描包详解

    SpringMVC和Spring的配置文件扫描包详解

    这篇文章主要介绍了SpringMVC和Spring的配置文件扫描包,本文给大家介绍的非常详细,具有一定的参考借鉴价值 ,需要的朋友可以参考下
    2019-05-05
  • 详解SpringCloud eureka服务状态监听

    详解SpringCloud eureka服务状态监听

    这篇文章主要介绍了详解SpringCloud eureka服务状态监听,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-07-07
  • Java计算两个时间相差的秒数怎么算

    Java计算两个时间相差的秒数怎么算

    这篇文章主要介绍了Java计算两个时间相差的秒数,通过实例代码补充介绍了Java 获取两个时间的时间差(时、分、秒)问题,感兴趣的朋友跟随小编一起看看吧
    2024-03-03
  • Java中 log4j日志级别配置详解

    Java中 log4j日志级别配置详解

    这篇文章主要介绍了Java中 log4j日志级别配置详解,需要的朋友可以参考下
    2018-01-01
  • 使用sharding-jdbc实现水平分库+水平分表的示例代码

    使用sharding-jdbc实现水平分库+水平分表的示例代码

    本文主要介绍了使用sharding-jdbc实现水平分库+水平分表,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-12-12
  • Java中HashMap如何解决哈希冲突

    Java中HashMap如何解决哈希冲突

    本文主要介绍了Java中HashMap如何解决哈希冲突,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-05-05
  • MybatisPlus自带的queryWrapper实现时间倒序方式

    MybatisPlus自带的queryWrapper实现时间倒序方式

    这篇文章主要介绍了MybatisPlus自带的queryWrapper实现时间倒序方式,具有很好的参考价值,希望对的有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-01-01
  • Spring Boot Admin监控服务如何使用

    Spring Boot Admin监控服务如何使用

    这篇文章主要介绍了Spring Boot Admin监控服务如何使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-04-04

最新评论