Java的内存泄漏

Java的内存泄漏

developerWorks
文档选项
将打印机的版面设置成横向打印模式

打印本页

将此页作为电子邮件发送

将此页作为电子邮件发送


级别: 初级

欧阳辰 (yeekee@sina.com),
周欣 (mailto:zhouxin@sei.pku.edu.cn),

2002 年 10 月 21 日

Java的一个重要优点就是通过垃圾收集器(Garbage Collection,GC)自动管理内存的回收,程序员不需要通过调用函数来释放内存。因此,很多程序员认为Java不存在内存泄漏问题,或者认为即使有内存泄漏也不是程序的责任,而是GC或JVM的问题。其实,这种想法是不正确的,因为Java也存在内存泄露,但它的表现与C++不同。

问题的提出

 

Java的一个重要优点就是通过垃圾收集器(Garbage Collection,GC)自动管理内存的回收,程序员不需要通过调用函数来释放内存。因此,很多程序员认为Java不存在内存泄漏问题,或者认为即使有内存泄漏也不是程序的责任,而是GC或JVM的问题。其实,这种想法是不正确的,因为Java也存在内存泄露,但它的表现与C++不同。

随着越来越多的服务器程序采用Java技术,例如JSP,Servlet, EJB等,服务器程序往往长期运行。另外,在很多嵌入式系统中,内存的总量非常有限。内存泄露问题也就变得十分关键,即使每次运行少量泄漏,长期运行之后,系统也是面临崩溃的危险。





回页首


Java是如何管理内存

 

为了判断Java中是否有内存泄露,我们首先必须了解Java是如何管理内存的。Java的内存管理就是对象的分配和释放问题。在Java中,程序员需要通过关键字new为每个对象申请内存空间 (基本类型除外),所有的对象都在堆 (Heap)中分配空间。另外,对象的释放是由GC决定和执行的。在Java中,内存的分配是由程序完成的,而内存的释放是有GC完成的,这种收支两条线的方法确实简化了程序员的工作。但同时,它也加重了JVM的工作。这也是Java程序运行速度较慢的原因之一。因为,GC为了能够正确释放对象,GC必须监控每一个对象的运行状态,包括对象的申请、引用、被引用、赋值等,GC都需要进行监控。

监视对象状态是为了更加准确地、及时地释放对象,而释放对象的根本原则就是该对象不再被引用。

为了更好理解GC的工作原理,我们可以将对象考虑为有向图的顶点,将引用关系考虑为图的有向边,有向边从引用者指向被引对象。另外,每个线程对象可以作为一个图的起始顶点,例如大多程序从main进程开始执行,那么该图就是以main进程顶点开始的一棵根树。在这个有向图中,根顶点可达的对象都是有效对象,GC将不回收这些对象。如果某个对象 (连通子图)与这个根顶点不可达(注意,该图为有向图),那么我们认为这个(这些)对象不再被引用,可以被GC回收。

以下,我们举一个例子说明如何用有向图表示内存管理。对于程序的每一个时刻,我们都有一个有向图表示JVM的内存分配情况。以下右图,就是左边程序运行到第6行的示意图。


图1

Java使用有向图的方式进行内存管理,可以消除引用循环的问题,例如有三个对象,相互引用,只要它们和根进程不可达的,那么GC也是可以回收它们的。这种方式的优点是管理内存的精度很高,但是效率较低。另外一种常用的内存管理技术是使用计数器,例如COM模型采用计数器方式管理构件,它与有向图相比,精度行低(很难处理循环引用的问题),但执行效率很高。





回页首


什么是Java中的内存泄露

 

下面,我们就可以描述什么是内存泄漏。在Java中,内存泄漏就是存在一些被分配的对象,这些对象有下面两个特点,首先,这些对象是可达的,即在有向图中,存在通路可以与其相连;其次,这些对象是无用的,即程序以后不会再使用这些对象。如果对象满足这两个条件,这些对象就可以判定为Java中的内存泄漏,这些对象不会被GC所回收,然而它却占用内存。

在C++中,内存泄漏的范围更大一些。有些对象被分配了内存空间,然后却不可达,由于C++中没有GC,这些内存将永远收不回来。在Java中,这些不可达的对象都由GC负责回收,因此程序员不需要考虑这部分的内存泄露。

通过分析,我们得知,对于C++,程序员需要自己管理边和顶点,而对于Java程序员只需要管理边就可以了(不需要管理顶点的释放)。通过这种方式,Java提高了编程的效率。


图2

因此,通过以上分析,我们知道在Java中也有内存泄漏,但范围比C++要小一些。因为Java从语言上保证,任何对象都是可达的,所有的不可达对象都由GC管理。

对于程序员来说,GC基本是透明的,不可见的。虽然,我们只有几个函数可以访问GC,例如运行GC的函数System.gc(),但是根据Java语言规范定义, 该函数不保证JVM的垃圾收集器一定会执行。因为,不同的JVM实现者可能使用不同的算法管理GC。通常,GC的线程的优先级别较低。JVM调用GC的策略也有很多种,有的是内存使用到达一定程度时,GC才开始工作,也有定时执行的,有的是平缓执行GC,有的是中断式执行GC。但通常来说,我们不需要关心这些。除非在一些特定的场合,GC的执行影响应用程序的性能,例如对于基于Web的实时系统,如网络游戏等,用户不希望GC突然中断应用程序执行而进行垃圾回收,那么我们需要调整GC的参数,让GC能够通过平缓的方式释放内存,例如将垃圾回收分解为一系列的小步骤执行,Sun提供的HotSpot JVM就支持这一特性。

下面给出了一个简单的内存泄露的例子。在这个例子中,我们循环申请Object对象,并将所申请的对象放入一个Vector中,如果我们仅仅释放引用本身,那么Vector仍然引用该对象,所以这个对象对GC来说是不可回收的。因此,如果对象加入到Vector后,还必须从Vector中删除,最简单的方法就是将Vector对象设置为null。

Vector v=new Vector(10);
for (int i=1;i<100; i++)
{
	Object o=new Object();
	v.add(o);
	o=null;	
}

//此时,所有的Object对象都没有被释放,因为变量v引用这些对象。



回页首


如何检测内存泄漏

 

最后一个重要的问题,就是如何检测Java的内存泄漏。目前,我们通常使用一些工具来检查Java程序的内存泄漏问题。市场上已有几种专业检查Java内存泄漏的工具,它们的基本工作原理大同小异,都是通过监测Java程序运行时,所有对象的申请、释放等动作,将内存管理的所有信息进行统计、分析、可视化。开发人员将根据这些信息判断程序是否有内存泄漏问题。这些工具包括Optimizeit Profiler,JProbe Profiler,JinSight , Rational 公司的Purify等。

下面,我们将简单介绍Optimizeit的基本功能和工作原理。

Optimizeit Profiler版本4.11支持Application,Applet,Servlet和Romote Application四类应用,并且可以支持大多数类型的JVM,包括SUN JDK系列,IBM的JDK系列,和Jbuilder的JVM等。并且,该软件是由Java编写,因此它支持多种操作系统。Optimizeit系列还包括Thread Debugger和Code Coverage两个工具,分别用于监测运行时的线程状态和代码覆盖面。

当设置好所有的参数了,我们就可以在OptimizeIt环境下运行被测程序,在程序运行过程中,Optimizeit可以监视内存的使用曲线(如下图),包括JVM申请的堆(heap)的大小,和实际使用的内存大小。另外,在运行过程中,我们可以随时暂停程序的运行,甚至强行调用GC,让GC进行内存回收。通过内存使用曲线,我们可以整体了解程序使用内存的情况。这种监测对于长期运行的应用程序非常有必要,也很容易发现内存泄露。


图3

在运行过程中,我们还可以从不同视角观查内存的使用情况,Optimizeit提供了四种方式:

  • 堆视角。 这是一个全面的视角,我们可以了解堆中的所有的对象信息(数量和种类),并进行统计、排序,过滤。了解相关对象的变化情况。
  • 方法视角。通过方法视角,我们可以得知每一种类的对象,都分配在哪些方法中,以及它们的数量。
  • 对象视角。给定一个对象,通过对象视角,我们可以显示它的所有出引用和入引用对象,我们可以了解这个对象的所有引用关系。
  • 引用图。 给定一个根,通过引用图,我们可以显示从该顶点出发的所有出引用。

在运行过程中,我们可以随时观察内存的使用情况,通过这种方式,我们可以很快找到那些长期不被释放,并且不再使用的对象。我们通过检查这些对象的生存周期,确认其是否为内存泄露。在实践当中,寻找内存泄露是一件非常麻烦的事情,它需要程序员对整个程序的代码比较清楚,并且需要丰富的调试经验,但是这个过程对于很多关键的Java程序都是十分重要的。

综上所述,Java也存在内存泄露问题,其原因主要是一些对象虽然不再被使用,但它们仍然被引用。为了解决这些问题,我们可以通过软件工具来检查内存泄露,检查的主要原理就是暴露出所有堆中的对象,让程序员寻找那些无用但仍被引用的对象。



参考资料

文章:

Jim Patrick, Handling memory leaks in Java programs,

http://www.ibm.com/developerworks/library/j-leaks/index.html

Ed Lycklama, Does Java Technology Have Memory Leaks?

http://www.klgroup.com/javaone

Sun,The Java HotSpot Virtual Machine, Technical White Paper

 

软件:

Sitraka Software's Jprobe http://www.sitraka.com

Boland Software's Optimizeit http://optimizeit

IBM alphaWorks' Jinsight http://www.alphaworks.ibm.com/tech/jinsight



作者简介

 

欧阳辰,北京大学计算机硕士毕业,98年起开始研究基于java的软件开发、测试,参与开发、测试过多个基于Java的应用程序和Web服务项目。


 

周欣,北京大学计算机系在读博士生,主要研究方向:程序理解、逆向工程及软件度量,联系方式 zhouxin@sei.pku.edu.cn

Java如何测试内存泄漏 我们知道JVM有自动回收机制,那么我们该怎么去测试程序中发生的内存泄漏呢,那首先是让程序不要运行完,我们可以让其sleep一会儿; 以一个顺序表为例,代码如下: public class Sequence { private Object[] elem; private int usedSize; private static int FA... 阅读详情

相关推荐

几个内存泄漏的例子

几个内存泄漏的例子  new和delete要成对使用  new和delete要匹配 经常看到一些C++方面的书籍中这样提及到内存泄漏问题,这样的说法的意思是比较明白,但对于初学C++程序员还是很难掌握,所以下面举几个反面的例子,希望对大家有帮助。

java不存在内存泄露_Java的内存泄露

Java的内存泄露Published:06 May 2014Category:Java有垃圾回收,因此不会出现内存泄露。大错特错。这个说法存在好几个问题。尽管Java的确有垃圾回收器来回收那些不用的内存块,但你不要指望它能够点铁成金。GC减轻了开发人员肩上的负担,而原本的那些工作非常容易出错,不过并不是所有内存分配的问题它都能够解决。更糟糕的是,Java的设计允许它可以欺骗GC,使得它能够保留一些...

weixin_27219587的博客 497

MTK平台TP驱动设备树与GPIO配置实战解析

本文详细解析了MTK平台TP驱动开发中的设备树与GPIO配置实战。通过DCT工具配置GPIO引脚,结合设备树节点定义触摸参数,并分享驱动移植、编译调试技巧及常见问题解决方案,帮助开发者快速掌握MTK触摸驱动开发核心。

ice55的博客 235

java常见的几种内存溢出和解决方案

项目组最近在开发中经常会出现一些意想不到的内存溢出问题。下面我就说说我们常见的几种内存溢出吧!1.JVM Heap(堆)溢出:java.lang.OutOfMemoryError: Java heap spaceJVM在启动的时候会自动设置JVM Heap的值, 可以利用JVM提供的-Xmn -Xms -Xmx等选项可进行设置。Heap的大小是Young...

weixin_33894640的博客 808

PIC单片机应用开发实践教程(二): 新建工程

File---New ProjectMicrochip Embedded --- Standalone Project 选择所用MCU对应型号 点击 Finish 后,工程就建好了 至止,我们的一个新工程就建完成了!

qq_57798018的博客 2888

从零到英雄:Spring Boot 微服务架构全攻略

在数字化转型的时代,微服务架构已成为构建可扩展、高可用系统的首选方案。本文以“从零到英雄”为主题,详细指导读者使用Spring Boot快速构建微服务帝国。从基础环境搭建入手,逐步深入到服务发现、配置管理、负载均衡、断路器、API网关、安全认证、监控与部署等核心模块。通过大量代码示例和详细解释,包括中文注释,帮助初学者和中级开发者掌握Spring Boot的核心概念和技术实践。文章强调实际操作,涵盖RESTful API开发、数据库集成、容器化部署等内容,并讨论常见问题与优化策略。无论你是Java开发者还是

一个被知识诅咒的人 2700

Java内存泄漏概念、造成原因及检测方式(全)

本身java有垃圾回收器GC,可以内存管理,但为什么还会造成内存泄漏(内存泄漏不等于内存溢出),内存泄漏在项目实战或者企业项目是不被允许,甚至在企业面试中也是常考的题型。

码农研究僧的博客 6326

从零构建:基于Docker与FRR的OSPF虚拟网络实验室

本文详细介绍了如何利用Docker与FRR构建OSPF虚拟网络实验室,从环境设计到高级网络拓扑配置,再到实验验证与排错。通过容器化技术实现高效资源利用和快速部署,特别适合网络协议教学、企业网络架构验证等场景。

plum99的博客 222

java基础回顾第四章:面向对象(上)

类与对象,封装,方法,重载

weixin_43530798的博客 266

基于ANSYS的电磁兼容仿真教程

最近,在做某系统的EMC仿真,使用ANSYS套件,对仿真学习做简要记录。本书简介与目录如下:本书配套有:视频教程+工程源文件+彩色仿真图片,下载链接如下:(审核中)第1章 基础知识1.1 电磁兼容基础​​​MS2、EMC三要素:3、 国际无线电干扰特别委员会标准:CISPR标准4、电磁兼容测试认证:传导发射(CE)、传导敏感度(CS)、辐射发射(RE)和辐射敏感度(RS)测试。

weixin_42508010的博客 2057

【Web攻防】SQLMap实战进阶:从数据猜解到高权限渗透的全流程指南

本文介绍了SQLMap工具在Web安全渗透测试中的实战应用,重点讲解了数据猜解、高权限操作、复杂请求提交、Tamper脚本开发和指纹绕过等核心场景。文章提供了可直接复用的命令示例,包括数据库信息获取、文件读写、命令执行等操作,并详细说明了POST/JSON/Cookie注入的实现方法。同时,介绍了Tamper脚本的开发模板和指纹伪装技巧,帮助降低检测风险。最后强调SQLMap在自动化渗透全链路中的价值,从漏洞发现到权限提升的完整流程,并提供了优化测试效率的实用建议。所有技术内容仅限合法授权场景使用。

YsChunQiu777的博客 441

在java开发项目中内存泄漏的五大原因,遇到内存泄漏我们该怎么做,怎么避免内存泄漏

​内存泄漏(Memory Leak)是指程序在申请内存后,无法释放已不再使用的内存的情况。通俗来说,就是程序中某些对象已经不再被使用,但由于某些原因仍然被其他对象引用,导致垃圾回收器(Garbage Collector)无法将它们从内存中回收,最终造成内存资源浪费的现象。内存泄漏的本质是对象的生命周期管理不当。在 Java 等具备自动垃圾回收机制的语言中,对象的创建和销毁由系统自动管理,但如果代码中存在不合理的引用关系,会导致对象无法被及时回收,从而占用内存空间。

Chenchen0905_的博客 3260

YOLO11改进|卷积篇|引入SPDConv

YOLO11中添加SPDConv卷积

A1983Z的博客 3697

如何排查Java内存泄漏

没有经验的程序员经常认为Java的自动垃圾回收完全使他们免于担心内存管理。这是一个常见的误解:虽然垃圾收集器做得很好,但即使是最好的程序员也完全有可能成为严重破坏内存泄漏的牺牲品。让我解释一下。 当不必要地维护不再需要的对象引用时,会发生内存泄漏。这些泄漏很糟糕。首先,当程序消耗越来越多的资源时,它们会对计算机施加不必要的压力。更糟糕的是,检测这些泄漏可能很困难:静态分析通常很难精确识别这些冗余引用,现有的泄漏检测工具会跟踪和报告有关单个对象的细粒度信息,产生难以解释且缺乏精确度的结果。 换句话说,泄漏要么

sutianxiao的博客 2374

搞懂 ABAP 里的 Language Settings:登录语言、文本环境语言与 sy-langu 的真实含义

SAP系统中语言设置并非单一字段决定,而是由登录语言(logon language)和文本环境语言(text environment language)共同控制。登录语言在会话期间固定,而文本环境语言可通过SET LOCALE语句修改,影响文本处理、排序、异常显示等行为。开发中需区分两者:使用CL_ABAP_SYST方法获取登录语言,通过sy-langu或GET LOCALE获取当前文本环境语言。语言环境切换应谨慎处理并尽快恢复,避免影响会话中其他程序。在多语言场景下,正确处理语言设置对确保文本相关功能正常

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 1307

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

如何在 Java 中进行内存泄漏分析

确认是否发生内存泄漏:通过jstat观察 GC 状态,确认是否存在问题。生成和分析 Heap Dump:使用jmap获取 Heap Dump 文件,并利用 MAT 或 VisualVM 工具分析。定位问题和修复代码:找到内存泄漏的根源后,通过优化对象管理和生命周期修复问题。

Mylqs的博客 2472

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

Java内存泄漏分析和解决

内存泄漏:对象已经没有被应用程序使用,但是垃圾回收器没办法移除它们,因为还在被引用着。在Java中,内存泄漏就是存在一些被分配的对象,这些对象有下面两个特点,首先,这些对象是可达的,即在有向图中,存在通路可以与其相连;其次,这些对象是无用的,即程序以后不会再使用这些对象。如果对象满足这两个条件,这些对象就可以判定为Java中的内存泄漏,这些对象不会被GC所回收,然而它却占用内存。在C++中,内存泄漏的范围更大一些。

RayPick的博客 1万+

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

JAVA内存泄漏

JAVA内存泄漏 1.介绍 Java的一个重要特性是通过垃圾收集器(GC)自动管理内存的回收,而不需要程序员自己释放内存,理论上Java中所有不会再被使用的对象所占用的内存都可以被GC回收,但是Java还是存在内存泄漏。 2.内存分配 在Java程序中,我们通常使用new为对象分配内存,这些内存空间都在堆(Heap)上。例如: public class Demo1 { public static void main(String[] args) { Object object1 =

zh123456_789的博客 333

java 内存泄漏_如何排查Java内存泄漏?看完你就明白了

没有经验的程序员经常认为Java的自动垃圾回收完全使他们免于担心内存管理。这是一个常见的误解:虽然垃圾收集器做得很好,但即使是最好的程序员也完全有可能成为严重破坏内存泄漏的牺牲品。让我解释一下。当不必要地维护不再需要的对象引用时,会发生内存泄漏。这些泄漏很糟糕。首先,当程序消耗越来越多的资源时,它们会对计算机施加不必要的压力。更糟糕的是,检测这些泄漏可能很困难:静态分析通常很难精确识别这些冗余引用...

weixin_39601642的博客 402

Java内存泄漏

Java 的核心优势之一是在内置垃圾收集器(或简称GC )的帮助下进行自动内存管理。GC 隐式地负责分配和释放内存,因此能够处理大多数内存泄漏问题。虽然 GC 有效地处理了大部分内存,但它并不能保证万无一失的内存泄漏解决方案。GC 非常聪明,但并非完美无缺。内存泄漏仍然可能悄悄发生,即使是在认真的开发人员的应用程序中也是如此。仍然可能存在应用程序生成大量多余对象的情况,从而耗尽关键内存资源,有时会导致整个应用程序失败。内存泄漏是 Java 中的一个真正问题。

weixin_43541852的博客 1377

java中是否存在内存泄漏?什么情况下才是内存泄漏?

java中是否存在内存泄漏?什么情况下才是内存泄漏? 什么是Java中的内存泄露 在Java中,内存泄漏就是存在一些被分配的对象,这些对象有下面两个特点,首先,这些对象是可达的,即在有向图中,存在通路可以与其相连;其次,这些对象是无用的,即程序以后不会再使用这些对象。如果对象满足这两个条件,这些对象就可以判定为Java中的内存泄漏,这些对象不会被GC所回收,然而它却占用内存。 在C++中,内存泄漏...

qq_44941119的博客 943

Java和内存泄漏

总览 术语“内存泄漏”在Java中的使用方式不同于在其他语言中使用的方式。 通用术语中的“内存泄漏”是什么意思,在Java中如何使用? 维基百科的定义 当计算机程序消耗内存但无法将其释放回操作系统时,就会发生计算机科学中的内存泄漏(在此情况下为泄漏)。 JVM在启动时将堆保留为虚拟内存,并且直到退出后才将其归还。 该虚拟内存在使用时会变成主内存。 这就是为什么JVM的虚拟大小和驻...

最佳 Java 编程 216

java内存泄漏分析

  java.lang.OutOfMemoryError是工作中常见的异常,今天介绍下如何分析java内存泄漏。   java内存分析工具很多,JDK安装目录下自带就有很多优秀的分析工具。分析堆栈时我比较推荐使用MAT,方便,快速。 安装MAT 打开eclipse ---&gt;help---&gt;eclipse marketplace(我在公司一般会下载高版本的eclipse,它带有一个插...

wflh323的专栏 7154

java string 内存泄漏_Java内存泄漏

Java内存泄漏解释内存泄漏: 存在一些被分配的对象,满足两个特点:对象是可达的:在有向图中,存在通路与之相连.对象是无用的:程序以后不再使用这些对象.结果:消耗越来越多的内存资源,最终导致OutOfMemoryError。与C++的区别:C++:对象被分配内存空间,却不可达.Java:不可达的对象由GC回收.示例:Vector v = new Vector(10);for(int i = 0; ...

weixin_36222664的博客 328
上一篇: NetBeans IDE 4.1/5.0 Profiler 教程 --分析对象创建过程以查找内存泄漏
下一篇: Java内存泄露问题分析
mlxia
博客等级 码龄26年 28粉丝 410原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值