通过下面步骤能够非常easy产生内存泄露(程序代码不能訪问到某些对象,可是它们仍然保存在内存中):

  1. 应用程序创建一个长时间执行的线程(或者使用线程池,会更快地发生内存泄露)。
  2. 线程通过某个类载入器(能够自己定义)载入一个类。
  3. 该类分配了大块内存(比方new byte[1000000]),在某个静态变量存储一个强引用,然后在ThreadLocal中存储它自身的引用。分配额外的内存new byte[1000000]是可选的(类实例泄露已经足够了),可是这样会使内存泄露更快。
  4. 线程清理自己定义的类或者载入该类的类载入器。
  5. 反复以上步骤。

因为没有了对类和类载入器的引用,ThreadLocal中的存储就不能被訪问到。ThreadLocal持有该对象的引用,它也就持有了这个类及其类载入器的引用,类载入器持有它所载入的类的全部引用,这样GC无法回收ThreadLocal中存储的内存。在非常多JVM的实现中Java类和类载入器直接分配到permgen区域不运行GC,这样导致了更严重的内存泄露。

这样的泄露模式的变种之中的一个就是假设你常常又一次部署以不论什么形式使用了ThreadLocal的应用程序、应用容器(比方Tomcat)会非常easy发生内存泄露(因为应用容器使用了如前所述的线程,每次又一次部署应用时将使用新的类载入器)。

A2:

静态变量引用对象

1 class MemorableClass
{
2     static final ArrayList
list =
new ArrayList(100);
3 }

调用长字符串的String.intern()

1 String
str=readString();
//
read lengthy string any source db,textbox/jsp etc..
2 //
This will place the string in memory pool from which you cant remove
3 str.intern();

未关闭已打开流(文件,网络等)

1 try {
2     BufferedReader
br =
new BufferedReader(new FileReader(inputFile));
3     ...
4     ...
5 }
catch (Exception
e) {
6     e.printStacktrace();
7 }

未关闭连接

1 try {
2     Connection
conn = ConnectionFactory.getConnection();
3     ...
4     ...
5 }
catch (Exception
e) {
6     e.printStacktrace();
7 }

JVM的GC不可达区域

比方通过native方法分配的内存。

web应用在application范围的对象,应用未重新启动或者没有显式移除

getServletContext().setAttribute("SOME_MAP", map);

web应用在session范围的对象,未失效或者没有显式移除

session.setAttribute("SOME_MAP", map);

不对或者不合适的JVM选项

比方IBM JDK的noclassgc阻止了无用类的垃圾回收

A3:假设HashSet未正确实现(或者未实现)hashCode()或者equals(),会导致集合中持续添加�“副本”。假设集合不能地忽略掉它应该忽略的元素,它的大小就仅仅能持续增长,并且不能删除这些元素。

假设你想要生成错误的键值对,能够像以下这样做:

1 class BadKey
{
2    //
no hashCode or equals();
3    public final String
key;
4    public BadKey(String
key) {
this.key
= key; }
5 }
6  
7 Map
map = System.getProperties();
8 map.put(new BadKey("key"),
"value");
//
Memory leak even if your threads die.

A4:除了被遗忘的监听器,静态引用,hashmap中key错误/被改动或者线程堵塞不能结束生命周期等典型内存泄露场景,以下介绍一些不太明显的Java发生内存泄露的情况,主要是线程相关的。

  • Runtime.addShutdownHook后没有移除,即使使用了removeShutdownHook,由于ThreadGroup类对于未启动线程的bug,它可能不被回收,导致ThreadGroup发生内存泄露。
  • 创建但未启动线程,与上面的情形同样
  • 创建继承了ContextClassLoader和AccessControlContext的线程,ThreadGroup和InheritedThreadLocal的使用,全部这些引用都是潜在的泄露,以及全部被类载入器载入的类和全部静态引用等等。这对ThreadFactory接口作为重要组成元素整个j.u.c.Executor框架(java.util.concurrent)的影响非常明显,非常多开发者没有注意到它潜在的危急。并且非常多库都会依照请求启动线程。
  • ThreadLocal缓存,非常多情况下不是好的做法。有非常多基于ThreadLocal的简单缓存的实现,可是假设线程在它的期望生命周期外继续执行ContextClassLoader将发生泄露。除非真正必要不要使用ThreadLocal缓存。
  • 当ThreadGroup自身没有线程可是仍然有子线程组时调用ThreadGroup.destroy()。发生内存泄露将导致该线程组不能从它的父线程组移除,不能枚举子线程组。
  • 使用WeakHashMap,value直接(间接)引用key,这是个非常难发现的情形。这也适用于继承Weak/SoftReference的类可能持有对被保护对象的强引用。
  • 使用http(s)协议的java.net.URL下载资源。KeepAliveCache在系统ThreadGroup创建新线程,导致当前线程的上下文类载入器内存泄露。没有存活线程时线程在第一次请求时创建,所以非常有可能发生泄露。(在Java7中已经修正了,创建线程的代码合理地移除了上下文类载入器。)
  • 使用InflaterInputStream在构造函数(比方PNGImageDecoder)中传递new java.util.zip.Inflater(),不调用inflater的end()。不过new的话非常安全,但假设自己创建该类作为构造函数參数时调用流的close()不能关闭inflater,可能发生内存泄露。这并非真正的内存泄露由于它会被finalizer释放。但这消耗了非常多native内存,导致linux的oom_killer杀掉进程。所以这给我们的教训是:尽可能早地释放native资源。
  • java.util.zip.Deflater也一样,它的情况更加严重。好的地方可能是非常少用到Deflater。假设自己创建了Deflater或者Inflater记住必须调用end()。

怎样用Java编写一段代码引发内存泄露的更多相关文章

  1. 如何用Java编写一段代码引发内存泄露

    本文来自StackOverflow问答网站的一个热门讨论:如何用Java编写一段会发生内存泄露的代码. Q:刚才我参加了面试,面试官问我如何写出会发生内存泄露的Java代码.这个问题我一点思路都没有, ...

  2. Java编写高质量代码改善程序的151个建议

    第一章  Java开发中通用的方法和准则 建议1:不要在常量和变量中出现易混淆的字母: (i.l.1:o.0等). 建议2:莫让常量蜕变成变量: (代码运行工程中不要改变常量值). 建议3:三元操作符 ...

  3. java: web应用中不经意的内存泄露

    前面有一篇讲解如何在spring mvc web应用中一启动就执行某些逻辑,今天无意发现如果使用不当,很容易引起内存泄露,测试代码如下: 1.定义一个类App package com.cnblogs. ...

  4. ThreadLocal是否会引发内存泄露的分析(转)

    这篇文章,主要解决一下疑惑: 1. ThreadLocal.ThreadLocalMap中提到的弱引用,弱引用究竟会不会被回收? 2. 弱引用什么情况下回收? 3. JAVA的ThreadLocal和 ...

  5. ThreadLocal是否会引发内存泄露的分析 good

    这篇文章,主要解决一下疑惑: 1. ThreadLocal.ThreadLocalMap中提到的弱引用,弱引用究竟会不会被回收? 2. 弱引用什么情况下回收? 3. JAVA的ThreadLocal和 ...

  6. 关于c语言内存分配,malloc,free,和段错误,内存泄露

    1.   C语言的函数malloc和free (1) 函数malloc和free在头文件<stdlib.h>中的原型及参数        void * malloc(size_t size ...

  7. JS中由闭包引发内存泄露的深思

    目录 一个存在内存泄露的闭包实例 什么是内存泄露 JS的垃圾回收机制 什么是闭包 什么原因导致了内存泄露 参考 1.一个存在内存泄露的闭包实例 var theThing = null; var rep ...

  8. 初学Java,第一段代码

    public class myapp { public static void main(String[] args) { // TODO Auto-generated method stub Sys ...

  9. 编写一段代码,打印一个M行N列的二维数组转置。(交换行和列)

    import edu.princeton.cs.algs4.*; public class No_1_1_13 { public static void main(String[] args) { i ...

随机推荐

  1. Ubuntu 14.04下安装GitLab指南

    摘要 GitLab 是一个用于仓库管理系统的开源项目.使用Git作为代码管理工具,并在此基础上搭建起来的web服务. 在GitLab的官方网站上面对Ubuntu的支持也是很好的,有比较详尽的安装指南. ...

  2. Introduction to the Build Lifecycle

    Introduction to the Build Lifecycle Table Of Contents Build Lifecycle Basics Setting Up Your Project ...

  3. 基于visual Studio2013解决C语言竞赛题之0907删除记录

       题目

  4. android 调用系统打电话和发短,懒得记

     Intent intent = new Intent();         intent.setAction(Intent.ACTION_CALL);         intent.setData( ...

  5. 关于运行robotium提示连接不上jar问题

    robotium运行测试helloworld报错: java.lang.NoClassDefFoundError: com.jayway.android.robotium.solo.Solo at c ...

  6. 官方发布的新版本Qt已经不支持XP了,要自己从源代码编译

    官方发布的新版本Qt已经不支持XP了,要自己从源代码编译,编译选项里有个-target项,用来提供XP支持的,编译时加上-target xp就可以了 http://www.qtcn.org/bbs/r ...

  7. 动态绑定Gridview带模板列

    公司要做一个可以支持4种数据库(<!--数据库类型 (DLL专用) (SQL SERVER) (ORACLE) (ACCESS)(POSTGRE SQL)-->)的并且字段随表字段变化的可 ...

  8. hdu 3998 (dp+最大流)

    题意:求最长上升子序列的长度和数量. 分析:用dp求出最长上升子序列m,dp数组存的就是该元素为子序列结尾的长度,源点与长度为1的点建边,长度为m的与汇点连边,然后枚举任意两个元素,ai,aj(ai& ...

  9. 杭电ACM1408——盐水的故事

    简单的题目,RT,就能够写出代码.须要注意的是类型的应用,应该用浮点型. 以下的是AC的代码: #include <iostream> using namespace std; int m ...

  10. java设计模式之观察者模式(9)

    Java观察者模式的浅析 简单地说,观察者模式定义了一个一对多的依赖关系,让一个或多个观察者对象监察一个主题对象.这样一个主题对象在状态上的变化能够通知所有的依赖于此对象的那些观察者对象,使这些观察者 ...