一、Java内存回收机制
不论哪种语言的内存分配方式,都需要返回所分配内存的真实地址,也就是返回一个指针到内存块的首地址。Java中对象是采用new或者反射的方法创建的,这些对象的创建都是在堆(Heap)中分配的,所有对象的回收都是由Java虚拟机通过垃圾回收机制完成的。GC为了能够正确释放对象,会监控每个对象的运行状况,对他们的申请、引用、被引用、赋值等状况进行监控,Java会使用有向图的方法进行管理内存,实时监控对象是否可以达到,如果不可到达,则就将其回收,这样也可以消除引用循环的问题。在Java语言中,判断一个内存空间是否符合垃圾收集标准有两个:一个是给对象赋予了空值null,以下再没有调用过,另一个是给对象赋予了新值,这样重新分配了内存空间。
二、Java内存泄露引起原因
首先,什么是内存泄露?经常听人谈起内存泄露,但要问什么是内存泄露,没几个说得清楚。内存泄露是指无用对象(不再使用的对象)持续占有内存或无用对象的内存得不到及时释放,从而造成的内存空间的浪费称为内存泄露。内存泄露有时不严重且不易察觉,这样开发者就不知道存在内存泄露,但有时也会很严重,会提示你Out of memory。
那么,Java内存泄露根本原因是什么呢?长生命周期的对象持有短生命周期对象的引用就很可能发生内存泄露,尽管短生命周期对象已经不再需要,但是因为长生命周期对象持有它的引用而导致不能被回收,这就是java中内存泄露的发生场景。具体主要有如下几大类:
1、静态集合类引起内存泄露:
像HashMap、Vector等的使用最容易出现内存泄露,这些静态变量的生命周期和应用程序一致,他们所引用的所有的对象Object也不能被释放,因为他们也将一直被Vector等引用着。
例:
Static Vector v = new Vector(10);
for (int i = 1; i<100; i++)
{
Object o = new Object();
v.add(o);
o = null;
}//
在这个例子中,循环申请Object 对象,并将所申请的对象放入一个Vector 中,如果仅仅释放引用本身(o=null),那么Vector 仍然引用该对象,所以这个对象对GC 来说是不可回收的。因此,如果对象加入到Vector 后,还必须从Vector 中删除,最简单的方法就是将Vector对象设置为null。
2、当集合里面的对象属性被修改后,再调用remove()方法时不起作用。
例:
public static void main(String[] args)
{
Set<Person> set = new HashSet<Person>();
Person p1 = new Person("唐僧","pwd1",25);
Person p2 = new Person("孙悟空","pwd2",26);
Person p3 = new Person("猪八戒","pwd3",27);
set.add(p1);
set.add(p2);
set.add(p3);
System.out.println("总共有:"+set.size()+" 个元素!"); //结果:总共有:3 个元素!
p3.setAge(2); //修改p3的年龄,此时p3元素对应的hashcode值发生改变
set.remove(p3); //此时remove不掉,造成内存泄漏
set.add(p3); //重新添加,居然添加成功
System.out.println("总共有:"+set.size()+" 个元素!"); //结果:总共有:4 个元素!
for (Person person : set)
{
System.out.println(person);
}
}
3、监听器
在java 编程中,我们都需要和监听器打交道,通常一个应用当中会用到很多监听器,我们会调用一个控件的诸如addXXXListener()等方法来增加监听器,但往往在释放对象的时候却没有记住去删除这些监听器,从而增加了内存泄漏的机会。
4、各种连接
比如数据库连接(dataSourse.getConnection()),网络连接(socket)和io连接,除非其显式的调用了其close()方法将其连接关闭,否则是不会自动被GC 回收的。对于Resultset 和Statement 对象可以不进行显式回收,但Connection 一定要显式回收,因为Connection 在任何时候都无法自动回收,而Connection一旦回收,Resultset 和Statement 对象就会立即为NULL。但是如果使用连接池,情况就不一样了,除了要显式地关闭连接,还必须显式地关闭Resultset Statement 对象(关闭其中一个,另外一个也会关闭),否则就会造成大量的Statement 对象无法释放,从而引起内存泄漏。这种情况下一般都会在try里面去的连接,在finally里面释放连接。
5、内部类和外部模块等的引用
内部类的引用是比较容易遗忘的一种,而且一旦没释放可能导致一系列的后继类对象没有释放。此外程序员还要小心外部模块不经意的引用,例如程序员A 负责A 模块,调用了B 模块的一个方法如:
public void registerMsg(Object b);
这种调用就要非常小心了,传入了一个对象,很可能模块B就保持了对该对象的引用,这时候就需要注意模块B 是否提供相应的操作去除引用。
6、单例模式
不正确使用单例模式是引起内存泄露的一个常见问题,单例对象在被初始化后将在JVM的整个生命周期中存在(以静态变量的方式),如果单例对象持有外部对象的引用,那么这个外部对象将不能被jvm正常回收,导致内存泄露,考虑下面的例子:
class A{
public A(){
B.getInstance().setA(this);
}
....
}
//B类采用单例模式
class B{
private A a;
private static B instance=new B();
public B(){}
public static B getInstance(){
return instance;
}
public void setA(A a){
this.a=a;
}
//getter...
}
显然B采用singleton模式,它持有一个A对象的引用,而这个A类的对象将不能被回收。想象下如果A是个比较复杂的对象或者集合类型会发生什么情况
相关推荐
### Java内存泄漏解决方案详解 #### 一、Java内存泄漏概述 在Java开发过程中,经常会遇到内存泄漏的问题,尤其是在长时间运行的应用程序中更为常见。本文将详细介绍如何解决Java内存泄漏问题,帮助开发者更好地...
### Java内存模型详解 #### 1. JMM简介 ##### i. 内存模型概述 Java内存模型(Java Memory Model, JMM)是Java虚拟机(JVM)的一部分,用于规定程序中的各种变量(包括实例字段、静态字段和数组元素等)在多个...
### Java内存分配机制详解 #### 一、引言 Java作为一种广泛应用的编程语言,其内存管理机制对于确保程序高效稳定运行至关重要。本文旨在详细介绍Java内存分配机制中的几个关键概念:寄存器、栈、堆、静态域、常量...
### Java内存泄漏详解 #### JVM内存管理概览 在探讨Java内存泄漏之前,我们先简要回顾一下JVM(Java虚拟机)的基本架构及其内存管理机制。这有助于更好地理解内存泄漏的发生原因及其解决方法。 ##### 类装载子...
Java内存泄露是指Java应用程序中由于某些原因导致的内存不能被正确释放,导致JVM OutOfMemory的错误。本文通过一个Demo来介绍ThreadLocal和ClassLoader导致内存泄露最终OutOfMemory的场景。 知识点1:ThreadLocal...
Java内存模型详解JMM Java内存模型(Java Memory Model,JMM)是Java虚拟机(JVM)中的一种内存模型,它描述了程序中各个变量之间的关系,以及在实际计算机系统中将变量存储到内存和从内存中取出变量这样的底层细节...
#### 三、Java内存管理机制详解 Java的内存管理机制主要包括以下几个方面: - **堆内存分配**:大部分Java对象都存储在堆内存中,而基本数据类型则通常存储在栈内存中。 - **垃圾回收**:GC会周期性地扫描堆内存,...
本文将深入探讨Java内存溢出的原因、表现以及如何解决。 1. **Java内存结构** Java内存主要分为堆内存(Heap)和栈内存(Stack),堆是存储对象实例的主要区域,而栈主要用于存储基本类型和对象引用。除此之外,...
### Java内存泄露、溢出检查方法及工具详解 #### 一、引言 在实际的项目开发和运维过程中,经常会遇到Java应用程序出现内存溢出(`java.lang.OutOfMemoryError`)的情况。这类问题不仅影响应用程序的稳定性和性能...
### Java内存空间详解 #### 一、Java内存机制概述 Java程序在运行过程中涉及的内存主要分为两大类:栈内存和堆内存。 1. **栈内存**:主要用于存储局部变量和对象的引用变量。栈内存的特点是先进后出,即先压入的...
04、导致JVM内存泄露的ThreadLocal详解_ev04、导致JVM内存泄露的ThreadLocal详解_ev04、导致JVM内存泄露的ThreadLocal详解_ev04、导致JVM内存泄露的ThreadLocal详解_ev04、导致JVM内存泄露的ThreadLocal详解_ev04、...
"Java高级知识点详解系列"聚焦于几个核心领域:Java内存管理、泛型以及反射。这些概念在实际开发中至关重要,理解它们能够帮助开发者写出更高效、更灵活且更易于维护的代码。 1. **Java内存**:Java内存主要涉及堆...
**内存泄漏的常见原因** 1. 静态集合类:如果静态集合类(如ArrayList、HashMap等)中保存了大量对象的引用,即使这些对象在其他地方已经不再使用,由于静态引用的存在,GC也无法回收。 2. 异常处理中的匿名内部类...
### 关于Java内存泄露问题解决 #### 引言:Java内存管理的核心——垃圾回收机制(GC) Java作为当今产业界和学术界最炙手可热的编程语言之一,以其独特的安全性和可移植性赢得了广泛的应用,尤其是在服务器端编程...
### Linux 内存泄露查找详解 #### 一、引言 在进行Linux C语言编程时,内存管理一直是程序员关注的重点之一。特别是在动态内存分配场景下,如果不妥善处理,很容易出现内存泄露的问题。内存泄露不仅会消耗系统资源...
Java内存泄露详解 内存泄露是编程中一个重要的问题,尤其在Java这样的高级语言中,它可能导致系统性能下降,甚至导致系统崩溃。本文将深入探讨Java中的内存泄露,包括其定义、分类、后果以及如何检测和防止。 **...
#### 三、Java内存泄漏 1. **定义**:内存泄漏是指已经分配出去的内存没有被及时回收,造成内存浪费。 2. **常见原因**: - **对象长期被持有**:如果对象长期被引用而没有被正确地释放,会导致这部分内存无法被...
通过深入了解Java内存机制,我们可以更好地管理应用程序的内存使用,避免出现内存泄漏等问题。此外,对于本机内存的理解有助于我们更全面地诊断和解决问题。随着Java应用程序变得越来越复杂,合理配置和优化内存管理...
Java内存泄露:诊断与解决方案详解 一、Java内存泄露概览 Java内存泄露是指在Java应用程序运行过程中,已经不再使用的对象或数据结构由于某种原因未能被垃圾回收器(Garbage Collector,GC)回收,导致系统内存...
### JAVA内存泄漏详解 #### 一、JAVA内存泄漏概述 在Java编程中,内存泄漏是一个常见但又极其棘手的问题。内存泄漏指的是程序在运行过程中不断申请内存却未能释放已不再使用的内存空间,最终导致可用内存减少乃至...