处理 Java 程序中的内存漏洞

  Java 程序中也有内存漏洞?当然有。与流行的观念相反,在 Java 编程中,内存管理仍然是需要考虑的问题。在本文中,您将了解到什么会导致内存漏洞以及何时应该关注这些漏洞。您还有机会实践一下在您自己的项目中解决漏洞问题。

Java 程序中的内存漏洞是如何显现出来的
  大多数程序员都知道,使用像 Java 这样的编程语言的一大好处就是,他们不必再担心内存的分配和释放问题。您只须创建对象,当应用程序不再需要这些对象时,Java 会通过一种称为“垃圾收集”的机制将这些对象删除。这种处理意味着 Java 已经解决了困扰其他编程语言的烦人问题 -- 可怕的内存漏洞。真的是这样的吗?

  在深入讨论之前,我们先回顾一下垃圾收集的工作方式。垃圾收集器的工作是发现应用程序不再需要的对象,并在这些对象不再被访问或引用时将它们删除。垃圾收集器从根节点(在 Java 应用程序的整个生存周期内始终存在的那些类)开始,遍历被引用的所有节点进行清除。在它遍历这些节点的同时,它跟踪哪些对象当前正被引用着。任何类只要不再被引用,它就符合垃圾收集的条件。当删除这些对象以后,就可将它们所占用的内存资源返回给 Java 虚拟机 (JVM)。

  所以的确是这样,Java 代码不要求程序员负责内存的管理和清除,它会自动对无用的对象执行垃圾收集。但是,我们要紧记的一点是仅当一个对象不再被引用时才会被统计为无用。图 1 说明了这个概念。

aspectratio="t">

  图 1. 无用但仍被引用的对象

  上面说明了在 Java 应用程序执行期间具有不同生存周期的两个类。类 A 首先被实例化,并会在很长一段时间或程序的整个生存期内存在。在某个时候,类 B 被创建,类 A 添加对这个新创建的类的一个引用。现在,我们假定类 B 是某个用户界面小部件,它由用户显示甚至解除。如果没有清除类 A 对 B 的引用,则即便不再需要类 B,并且即便在执行下一个垃圾收集周期以后,类 B 仍将存在并占用内存空间。

何时应该关注内存漏洞
  如果您的程序在执行一段时间以后发出 java.lang.OutOfMemoryError 错误,则内存漏洞肯定是一个重大嫌疑。除了这种明显的情况之外,何时还应该关注内存漏洞呢?持完美主义观点的程序员肯定会回答,应该查找并纠正所有内存漏洞。但是,在得出这个结论之前,还有几个方面需要考虑,包括程序的生存期和漏洞的大小。

  完全有这样的可能,垃圾收集器在应用程序的生存期内可能始终不会运行。不能保证 JVM 何时以及是否会调用垃圾收集器 -- 即便程序显式地调用 System.gc() 也是如此。通常,在当前的可用内存能够满足程序的内存需求时,JVM 不会自动运行垃圾收集器。当可用内存不能满足需求时,JVM 将首先尝试通过调用垃圾收集来释放出更多的可用内存。如果这种尝试仍然不能释放足够的资源,JVM 将从操作系统获取更多的内存,直至达到允许的最大极限。

  例如,考虑一个小型 Java 应用程序,它显示一些用于修改配置的简单用户界面元素,并且它有一个内存漏洞。很可能到应用程序关闭时也不会调用垃圾收集器,因为 JVM 很可能有足够的内存来创建程序所需的全部对象,而此后可用内存则所剩无几。因此,在这种情况下,即使某些“死”对象在程序执行时占用着内存,它实际上并没有什么用途。

  如果正在开发的 Java 代码要全天 24 小时在服务器上运行,则内存漏洞在此处的影响就比在我们的配置实用程序中的影响要大得多。在要长时间运行的某些代码中,即使最小的漏洞也会导致 JVM 耗尽全部可用内存。

  在相反的情况下,即便程序的生存期较短,如果存在分配大量临时对象(或者若干吞噬大量内存的对象)的任何 Java 代码,而且当不再需要这些对象时也没有取消对它们的引用,则仍然可能达到内存极限。

  最后一种情况是内存漏洞无关紧要。我们不应该认为 Java 内存漏洞像其他语言(如 C++)中的漏洞那样危险,在那些语言中内存将丢失,且永远不会被返回给操作系统。在 Java 应用程序中,我们使不需要的对象依附于操作系统为 JVM 所提供的内存资源。所以从理论上讲,一旦关闭 Java 应用程序及其 JVM,所分配的全部内存将被返回给操作系统。

确定应用程序是否有内存漏洞
  为了查看在 Windows NT 平台上运行的某个 Java 应用程序是否有内存漏洞,您可能试图在应用程序运行时观察“任务管理器”中的内存设置。但是,在观察了运行中的几个 Java 应用程序以后,您会发现它们比本地应用程序占用的内存要多得多。我做过的一些 Java 项目要使用 10 到 20 MB 的系统内存才能启动。而操作系统自带的 Windows Explorer 程序只需 5 MB 左右的内存。

  在 Java 应用程序内存使用方面应注意的另一点是,这个典型程序在 IBM JDK 1.1.8 JVM 中运行时占用的系统内存越来越多。似乎直到为它分配非常多的物理内存以后它才开始向系统返回内存。这些情况是内存漏洞的征兆吗?

  要理解其中的缘由,我们必须熟悉 JVM 如何将系统内存用作它的堆。当运行 java.exe 时,您使用一定的选项来控制垃圾收集堆的起始大小和最大大小(分别用 -ms 和 -mx 表示)。Sun JDK 1.1.8 的默认起始设置为 1 MB,默认最大设置为 16 MB。IBM JDK 1.1.8 的默认最大设置为系统总物理内存大小的一半。这些内存设置对 JVM 在用尽内存时所执行的操作有直接影响。JVM 可能继续增大堆,而不等待一个垃圾收集周期的完成。

  这样,为了查找并最终消除内存漏洞,我们需要使用比任务监视实用程序更好的工具。当您试图调试内存漏洞时,内存调试程序(请参阅参考资源)可能派得上用场。这些程序通常会显示堆中的对象数、每个对象的实例数和这些对象所占用的内存等信息。此外,它们也可能提供有用的视图,这些视图可以显示每个对象的引用和引用者,以便您跟踪内存漏洞的来源。

下面我将说明我是如何用 Sitraka Software 的 JProbedebugger 检测和去除内存漏洞的,以使您对这些工具的部署方式以及成功去除漏洞所需的过程有所了解。

内存漏洞的一个示例
  本例集中讨论一个问题,我们部门当时正在开发一个商业发行版软件,这是一个 Java JDK 1.1.8 应用程序,一个测试人员花了几个小时研究这个程序才最终使这个问题显现出来。这个 Java 应用程序的基本代码和包是由几个不同的开发小组在不同的时间开发的。我猜想,该应用程序中意外出现的内存漏洞是由那些没有真正理解别人开发的代码的程序员造成的。

  我们正在讨论的 Java 代码允许用户为 Palm 个人数字助理创建应用程序,而不必编写任何 Palm OS 本地代码。通过使用图形用户界面,用户可以创建窗体,向窗体中添加控件,然后连接这些控件的事件来创建 Palm 应用程序。测试人员发现,随着不断创建和删除窗体和控件,这个 Java 应用程序最终会耗尽内存。开发人员没有检测到这个问题,因为他们的机器有更多的物理内存。

  为了研究这个问题,我用 JProbe 来确定什么地方出了差错。尽管用了 JProbe 所提供的强大工具和内存快照,研究仍然是一个冗长乏味、不断重复的过程,首先要确定出现内存漏洞的原因,然后修改代码,最后还得检验结果。

  JProbe 提供几个选项,用来控制调试期间实际记录哪些信息。经过几次试验以后

点击复制链接 与好友分享!回本站首页
您对本文章有什么意见或着疑问吗?请到论坛讨论您的关注和建议是我们前行的参考和动力
上一篇:Java: 使用 finally 关键字来避免资源漏洞
下一篇:VJ6.0的使用方法(1)概述、VJ6的获得与安装
相关文章

Java异常处理的陋习展播

学习用于异常处理的terminate()函数

轻松处理命令行参数

使用BigInteger处理大二进制数

构建更好的异常处理框架

教程/系统编程 在Java中处理日志记录

J2ME编程中时间处理全攻略

J2ME程序开发中随机数字处理全攻略

一个用于J2EE应用程序的异常处理框架

JSF导航规则与动作处理

图文推荐

处理 Java 程序中的内存漏洞
适配器模式
处理 Java 程序中的内存漏洞
Handler的介绍和使用
处理 Java 程序中的内存漏洞
struts2上传文件
处理 Java 程序中的内存漏洞
通过JFreeChart的饼状

处理 Java 程序中的内存漏洞

排行
热门
89 | HTML5绘制饼图示例(一)
85 | java.lang.ClassCastException: java
77 | java的int、char、long、float、doubl
73 | Spring3注解零配置
67 | 在java类中获取在.properties配置文件
67 | Tomcat使用MyEclipse远程调试Java代码
65 | java抓取动态生成的网页--吐槽
62 | Spring初始化容器
10种排序算法总结
java中static作用详解
Java读取txt文件
Eclipse使用入门教程
Spring定时器时间配置
Java中List转换为数组,数组转List
Java中23种经典设计模式详解
理解HTTP session原理及应用
文章
下载
读书
· Win2000下关闭无用端口
· 禁止非法用户登录综合设置 [win9x篇]
· 关上可恶的后门——消除NetBIOS隐患
· 网络入侵检测系统
· 潜伏在Windows默认设置中的陷井
· 调制解调器的不安全
· 构建Windows 2000服务器的安全防护林
· SQL Server 2000的安全配置
· Windows优化大师注册机源码
· Process Viewer 汉化版
· Aspcode动画教程
· WIN 2000服务器防止ICMP数据包攻击教程
· 实现网络隐身的简单方法
· 手工进行克隆帐号
· 用W32DASM破解网页合并器的密码
· 注册表操作动画教程
· 黑客攻防技术宝典:Web实战篇(第2版)
· 超级网管员——网络安全
· 代码大全(第二版)
· 软件之道:软件开发争议问题剖析
· CSS插件工具箱
· CSS入门经典(第3版)
· C#并行编程高级教程:精通.NET 4 Pa
· CMMI+敏捷整合开发
处理 Java 程序中的内存漏洞
Java中的递归原理分析
▪ 如何自学java迅速成为java高手
▪ Java学习这七年
▪ 一个Java程序员应该掌握的10项技能
▪ Java编程语言程序的认识误区
▪ java中的接口和抽象类是什么?
▪ Java中23种经典设计模式详解
▪ Java静态代码块(static block)调用陷
▪ Hibernate基础:Configuration
分类:默认分类 时间:2015-02-28 人气:2
本文关键词:
分享到:

相关文章

Copyright (C) quwantang.com, All Rights Reserved.

趣玩堂 版权所有 京ICP备15002868号

processed in 0.089 (s). 10 q(s)