知识大全 Java 程序里的内存泄漏
Posted 知
篇首语:少年意气强不羁,虎胁插翼白日飞。本文由小常识网(cha138.com)小编为大家整理,主要介绍了知识大全 Java 程序里的内存泄漏相关的知识,希望对你有一定的参考价值。
Java 程序里的内存泄漏 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!
Java 程序里的内存泄漏是如何表现的 大多数程序员都知道使用类似于 Java 的编程语言的好处之一就是他们无需再为内存的分配和释放所担心了 你只需要简单地创建对象 当它们不再为程序所需要时 Java 会自行通过一个被称为垃圾收集的机制将其移除 这个过程意味着 Java 已经解决了困扰其他编程语言的一个棘手的问题 可怕的内存泄漏 果真是这样的吗? 在进行深入讨论之前 让我们先回顾一下垃圾收集是如何进行实际工作的 垃圾收集器的工作就是找到程序不再需要的对象并在当它们不再被访问或引用时将它们移除掉 垃圾收集器从贯穿整个程序生命周期的类这个根节点开始 扫描所有引用到的节点 在遍历节点时 它跟踪那些被活跃引用着的对象 那些不再被引用的对象就满足了垃圾回收的条件 当这些对象被移除时被它们占用的内存资源会交还给 Java 虚拟机(JVM) 因此 Java 代码的确不需要程序员负责内存管理的清理工作 它自行对不再使用的对象进行垃圾收集 然而 需要记住的是 垃圾收集的关键在于一个对象在不再被引用时才被统计为不再使用 下图对这一概念进行了说明
上图表示在一个 Java 程序执行时具有不同的生命周期的两个类 类 A 首先被实例化 它存在的时间比较长 几乎贯穿整个进程的生命周期 在某个时间点 类 B 被创建 类 A 添加了一个对这个新建类的引用 我们假设类 B 是某个用于显示并返回用户指令的用户界面部件 尽管类 B 不再被使用 如果类 A 对类 B 的引用未被清除 类 B 将继续存在并占据内存空间 即使下一次垃圾收集被执行 什么时候需要注意内存泄漏? 如果在你的程序执行一段时间之后遇到 java lang OutOfMemoryError 的话 内存泄漏无疑是最值得怀疑的 除了这种明显的情况之外 什么时候需要考虑内存泄漏?完美主义的程序员会回答说所有的内存泄漏都需要进行审查和更改 然而 在跳到这一结论之前还需要考虑其他几点因素 包括程序的生命周期以及内存泄漏的大小 考虑一下在一个程序的生命周期里垃圾收集器可能从未执行的情况 无法保证什么时候 JVM 会调用垃圾收集 即使程序显式调用 System gc() 通常情况下 垃圾收集器不会自动运行 直到程序需要比目前可用内存还要多的内存 此时 JVM 会首先尝试调用垃圾收集器以获取更多可用内存 如果这个尝试仍旧不能够释放出足够的资源 JVM 将会从操作系统获取更多内存 直到达到所允许内存的最大值 举个例子来说 一个小型的 Java 应用程序 用来显示一些简单的配置修改的用户界面元素 出现了内存泄漏 垃圾收集器可能在程序关闭之前都不会被调用到 因为 JVM 可能总是有足够的内存来创建程序所需要的所有对象 因此 在这种情况下 即便是一些已死对象在程序运行的时候仍旧占据着内存 但这并不影响实际应用 如果开发中的 Java 代码将以每天 小时运行在服务器上 这时内存泄漏将会比上面的那个配置工具程序要明显的多了 即便是代码中最小的内存泄漏 在持续运行的情况下最终也将耗尽所有可用内存 相反的情况下 即使一个程序只是短暂存活 却分配了大量临时对象(或者少量的占用大量内存的对象) 在这些对象不再需要时没有取消引用 这样的 Java 代码也会达到内存限制 最后一个值得注意的问题是 不必过于担心(Java 程序所造成的)内存泄漏 Java 内存泄漏不应该被认为是像其他语言中所发生的那样危险 比如 C++ 的内存丢失将永远不会返回给操作系统 Java 应用程序中 我们把不再需要的却占据着内存资源的对象都交给 JVM 所以在理论上来说 一旦 Java 程序和它的 JVM 关闭掉 所有分配的内存都将归还给操作系统 如何断定程序具有内存泄漏 查看一个运行在 Windows NT 平台上的 Java 程序是否具有内存泄漏 你可以简单地在程序运行的时候去观察任务管理器中的内存设置 然而 在观察一些运行中的 Java 程序之后 你会发现 它们跟本地应用程序相比使用更多内存 我开发过的一些 Java 项目会启用 到 MB 的系统内存 与这个数字相比 本地的操作系统自带的 Windows Explorer 程序使用到 MB 另外一个关于 Java 程序的内存使用要注意的是典型的运行在 IBM JDK JVM 上的程序似乎在其运行时不断吞噬了越来越多的系统内存 程序似乎永远不会返回一些内存给操作系统 直到一个非常大的物理内存分配给它 这会不会就是内存泄漏的迹象? 要明白是怎么回事 我们需要熟悉 JVM 是如何将系统内存使用作自己的堆的 在运行 java exe 时 你可以使用一些特定的选项来控制垃圾收集的堆的启动容量和最大容量(分别是 ms 和 mx) Sun 的 JDK 默认使用 MB 的启动设置和 MB 的最大设置 IBM JDK 默认使用机器物理内存容量的一半作为最大设置 这些内存设置对 JVM 发生内存溢出时的做法具有直接影响 这时 JVM 可能会继续增长堆内存 而不是等待一个垃圾回收的结束 因此为了寻找并最终消除内存泄漏 我们需要比任务监视程序更好的工具 当你想检测内存泄漏的时候内存调试程序(参见下文的参考资料)可以派上用场了 这些程序通常会给你关于堆内存里对象的数量 每个对象实例的个数以及对象使用中的内存等一些信息 此外 它们还会提供很有用的视图 这些视图可以显示每个对象的引用和引用者 以便你跟踪内存漏洞的来源 接下来 我将展示如何使用 Sitraka Sofare 的 JProbe 调试工具来检测和消除内存泄漏 希望会对你就如何部署这些工具并成功消除内存泄漏产生一些启发 一个内存泄漏的例子 这个示例主要展示了我们部门开发的一个商业版应用的一个问题 这个问题在 JDK 上工作了几个小时后被测试人员找出来 这个 Java 应用程序的相关代码和包是由几个不同团队的程序员开发出来的 程序里出现的内存泄漏的原因 我怀疑 是由一些没有真正理解其他(团队)开发的代码的程序员所引起 讨论中的 Java 代码允许用户不必去写 Palm OS 本地代码来创建 Palm 个人数码助理应用 通过使用图形界面 用户可以创建表单 使用控件对它们进行填充 然后连接控件事件来创建 Palm 应用程序 测试人员发现 这个 Java 应用最终发生了内存溢出 表单和控件的创建和删除延时 开发人员并没有发现这个问题存在 因为他们的机器(相对 Palm)拥有着更多的物理内存 为了讨论这个问题 我使用了 JProbe 来断定问题的存在 即使拥有 JProde 提供的强大工具和内存快照 调查仍然是一个繁琐的 反复的过程 它涉及先确定内存泄漏的原因 然后做出代码更改并验证其效果
JProbe 有几个选项来控制在一次调试回话期间什么样的信息会被记录 经过一些试验后 我判定获取所需信息的最有效的方式是关掉性能数据收集 专注于捕获的堆数据 JProbe 提供了一个叫做运行时堆摘要的视图来显示 Java 应用程序在一段时间内使用的堆内存的数量 它同时也提供了一个工具栏按钮用来在需要时强制 JVM 执行垃圾收集 在想要看一下一个类的给定实例不再为 Java 应用程序需要时是否会被垃圾收集 这个功能是很有用的 下图显示了在一段时间内使用的堆存储量
在堆使用情况图中 蓝色部分表示已分配的堆空间量 我启动 Java 程序之后它达到了一个稳定点 我强制垃圾收集器执行 这由绿线之前的蓝色曲线的一个骤降表示(这条绿线表示一个检查点被插入) 接下来 我先是添加而后删掉了四个表单并再次调用垃圾收集器 检查点之后的蓝色曲线的水平线比检查点之前的蓝色曲线的水平线高的事实告诉我们很可能出现了内存泄漏 因为该程序已经回归其只有一个简单可见的表单的初始状态 我检查实例确认了泄漏 总之 结果表明 FormFrame 类(表单的主 UI 类)的数量在检查点之后增加了四个 寻找原因 要想将测试人员提交的问题隔离出来 第一步就是提供一些简单的 重复的测试用例 以上面那个例子为例 我发现简单地添加一个表单 删除这个表单 然后强制垃圾收集器的结果是一些关联到已经删除掉的表单的实例仍然存活着 这种问题通过 JProbe实例摘要视图来看是显而易见的 视图中统计了堆内存中每个类的实例的个数 要定位垃圾收集器工作时具体实例的引用 我使用了 JProbe 的引用画面 如下图所示 来断定哪些类仍然在引用已被删除掉的 FormFrame 类 这是调试这种问题的巧妙地方法之一 我通过它发现了很多不同的对象仍然在引用那些无用的对象 而通过试错来查明究竟是哪个引用者真正造成这个问题的过程却是相当耗时的 在这个案例中 根类(左上角红色的那个)是出现问题的起源 右侧用蓝色突出的那个类就是追踪到的 FormFrame 类
cha138/Article/program/Java/hx/201311/25565
相关参考
Java内存泄漏分析与解决方案 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! Java内存泄漏是
ArrayList就是传说中的动态数组就是Array的复杂版本它提供了如下一些好处动态的增加和减少元素灵活的设置数组的大小…… 认真阅读本文我相信一定会对你有帮助比如为什么ArrayList里面
安卓手机怎么将手机里的软件移动到内存卡上?直接在设置--应用程序---点进去就有移动到内存卡的选项如果有些程序本身不支持移动到SD卡的就要用第三方软件“钛备份”,进这个软件,所有的程序和内置程序全部可
大多Java程序员知道他们的程序通常不会被编译为本机代码而是被编译为由java虚拟机(JVM)执行的字节码格式然而很少有java程序员曾经看过字节码因为他们的工具不鼓励他们去看大多Java调试工具
JAVA执行JS文件里的程序 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!
发现Java虚拟机内存泄露问题 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!内存泄露问题对于程序来
Java有一个很好的地方就是java的垃圾收集机制这个机制集成于jvm的对程序员来说是隐藏且不透明的这种情况下如何得到某个对象消耗的内存呢? 曾经看到过有人用以下方法来计算在生成该obj
让Java程序只运行一个实例 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 一个程序可以在内存里
DataTable.NewRow内存泄漏问题 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 先看
未释放事件Handler可能导致内存泄漏 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 以前曾看