如何造成内存泄漏

这将是一个相当邪恶的职位-当您确实希望使某人的生活陷入困境时,您将在谷歌上搜索。 在Java开发领域,内存泄漏只是您在这种情况下会引入的错误类型。 为您的受害者保证几天甚至几周的办公室不眠之夜。

我们将在这篇文章中描述两次泄漏。 两者都很容易理解和复制。 泄漏源于现实世界中的案例研究,但为清楚起见,我们提取了演示案例,以使您更短,更简单。 但是请放心–在我们已经看到并修复了数百个泄漏之后–与演示的情况类似的情况比您预期的更普遍。

第一个闯入环的参赛者–臭名昭著的HashSet / HashMap解决方案,其中使用的键不具有或具有不正确的equals()/ hashCode( )解决方案。

class KeylessEntry {
 
   static class Key {
      Integer id;
 
      Key(Integer id) {
         this.id = id;
      }
 
      @Override
      public int hashCode() {
         return id.hashCode();
      }
   }
 
   public static void main(String[] args) {
      Map<key, string=""> m = new HashMap<key, string="">();
      while (true)
         for (int i = 0; i < 10000; i++)
            if (!m.containsKey(i))
               m.put(new Key(i), "Number:" + i);
   }
}

当您执行上面的代码时,您希望它可以永远运行而不会出现任何问题-毕竟,内置的幼稚缓存解决方案应该只扩展到10,000个元素,然后停止增长,因为所有键都已经存在于HashMap中 。 但是,情况并非如此-元素会继续添加,因为Key类在其hashCode()旁边不包含适当的equals()实现 。 该解决方案很容易–与以下示例类似,添加equals()方法的实现,您很高兴。 但是,在设法找到原因之前,您肯定已经失去了一些宝贵的脑细胞。

@Override
public boolean equals(Object o) {
   boolean response = false;
   if (o instanceof Key) {
      response = (((Key)o).id).equals(this.id);
   }
   return response;
}

让您的朋友保持清醒的第二个问题-一些操作中的字符串处理。 像魅力一样工作,尤其是与JVM版本差异结合使用时。 在JDK 7u6中更改了 String内部构件的工作方式,因此,如果您设法找到仅次要版本导致生产和登台不同的环境,那么您已经准备就绪 。 向您的朋友投掷类似于以下代码的代码,以进行调试,并想知道为什么问题不在生产中出现在其他任何地方。

class Stringer {
   static final int MB = 1024*512;
 
   static String createLongString(int length){
      StringBuilder sb = new StringBuilder(length);
      for(int i=0; i < length; i++)
         sb.append('a');
      sb.append(System.nanoTime());
      return sb.toString();
   }
 
   public static void main(String[] args){
      List<string> substrings = new ArrayList<string>();
      for(int i=0; i< 100; i++){
         String longStr = createLongString(MB);
         String subStr = longStr.substring(1,10);
         substrings.add(subStr);
      }
   }
}

上面的代码中发生的事情–当它在预JDK 7u6上运行时,返回的子字符串在下面保留了对〜1MB大字符串的引用。 因此,当使用-Xmx100m运行示例时,您将遇到意外的OutOfMemoryException。 将此与平台差异结合起来,在您正在尝试的环境中使用不同的JDK版本,第一批白发将蓬勃发展。 现在,如果您想掩盖自己的足迹,我们可以将一些更高级的概念添加到产品组合中,例如 3D水龙头

  • 在其他类加载器中加载已损坏的代码,并在丢弃原始类加载器后模仿类加载器泄漏 ,保留对加载的类的引用
  • 将有问题的代码隐藏到finalize()方法中,使症状真正不可预测
  • 将长时间运行的线程的棘手组合扔掉,这些线程将某些东西存储在ThreadPool所访问的ThreadLocals中–受控制的应用程序线程

希望我们能给您带来一些思考,并为您下次生气时提供一些技巧。 无数小时的核心调试保证。 除非您的朋友使用Plumbr ,否则当然会为他找到泄漏。 但是公然的市场营销方面,我希望我们能够在两个简单的例子中证明在Java中创建内存泄漏有多么容易。 你们中的大多数人都经历了追踪这样一个错误的难度。 因此,如果您喜欢这篇文章,请订阅我们的Twitter feed,以得到有关我们未来有关JVM性能调整的内容的警报。

参考: 如何通过我们的JCG合作伙伴 Nikita Salnikov- Tarnovski 造成内存泄漏 ,请访问Plumbr Blog博客。

翻译自: https://www.javacodegeeks.com/2013/04/how-to-create-a-memory-leak.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值