Java最显著的优势之一就是它的内存管理机制。你只需简单创建对象,然后Java垃圾回收机制便会小心的分配和释放内存。然而,事实并非如此简单,因为在Java应用程序中经常发生内存泄漏。
本教程说明了什么是内存泄漏,为什么会发生,以及如何防止它们。
1.什么是内存泄漏?
内存泄漏的定义: 对象不再被应用程序使用,但是垃圾回收器却不能移除它们,因为它们正在被引用。
要理解这个定义,我们需要理解对象在内存中的状态,下图说明了哪些是未被使用的以及哪些是未被引用的。
从图中可以看到被引用的对象和未被引用的对象。未被引用的对象将会被垃圾回收器回收,而被引用对象则不会被回收。未被引用的对象理所当然是未被使用的,因为没有其他的对象引用它。然而,未被使用的对象并不一定是未被引用的,其中一些是被引用的。这就是内存泄漏的起因。
2.为什么会发生内存泄漏?
让我们来看看下面这个例子,看看为什么内存泄漏会发生。在如下例子中,对象A引用了对象B。A的生命周期(t1—t4)要比B的生命周期(t2—t3)长很多。当B不再用于应用中时,A仍然持有对它的引用。在这种方式下,垃圾回收器就不能将B从内存中移除。这将可能导致出现内存不足的问题,因为如果A对更多的对象做同样的事情,那么内存中将会有很多无法被回收的对象,这将极度耗费内存空间。
也有可能B持有大量对其他对象的引用,这些被B引用的对象也不能够被回收。所有这些未被使用的对象将会耗费宝贵的内存空间。
3.如何阻止内存泄漏?
以下是一些阻止内存泄漏的快速动手技巧。
(1)注意集合类,例如HashMap,ArrayList,等等。因为它们是内存泄漏经常发生的地方。当它们被声明为静态时,它们的生命周期就同应用程序的生命周期一般长。
(2)注意事件监听器和回调,如果一个监听器已经注册,但是当这个类不再被使用时却未被注销,就会发生内存泄漏。
(3)“如果一个类管理它自己的内存,程序员应该对内存泄漏保持警惕。”[1] 很多时候当一个对象的成员变量指向其他对象时,不再使用时需要被置为null。
4.jdk1.6中substring()中内存泄漏问题:
substring(int beginIndex ,int endIndex)方法返回一个子字符串,返回的是从原字符串的beginIndex到endIndex-1之间的内容。
1
2
3
|
String x = "abcdef" ;
x = x.substring( 1 , 3 );
System.out.println(x); |
输出:
1
|
"bc" |
2.当substring()被调用的时候,内部发生什么事?
你或许会认为由于x是不可变的对象,当x被x.substring(1,3)返回的结果赋值后,它将指向一个全新的字符串如下图:
然而,这个图并不完全正确,或者说并没有完全表示出java 堆中真正发生的事情。那么当调用substring()的时候到底发生的了什么事呢?JDK 6与JDK7的substring方法实现有什么不一样呢?
3.JDK6中的substring()
java中字符串是通过字符数组来支持实现的,在JDK6中,String类包含3个域,char[] value、int offset、int count。分别用于存储真实的字符数组、数组的偏移量,以及String所包含的字符的个数。
当substring()方法被调用的时候,它会创建一个新的字符串对象,但是这个字符串的值在java 堆中仍然指向的是同一个数组,这两个字符串的不同在于他们的count和offset的值。
下面是jdk6中的原代码,是简化后只包含用来说明这个问题的关键代码:
1
2
3
4
5
6
7
8
9
10
11
|
//JDK 6 String( int offset, int count, char value[]) {
this .value = value;
this .offset = offset;
this .count = count;
} public String substring( int beginIndex, int endIndex) {
//check boundary
return new String(offset + beginIndex, endIndex - beginIndex, value);
} |
4.jdk6中substring()将会导致的问题
如果你有一个非常长的字符串,但是你仅仅只需要这个字符串的一小部分,这就会导致性能问题(译注:可能会造成内存泄露,这个bug很早以前就有提及),因为你需要的只是很小的部分,而这个子字符串却要包含整个字符数组,在jdk6中解决办法就是使用下面的方法,它会指向一个真正的子字符串。
1
|
x = x.substring(x, y) + ""
|
5.JDK7中的substring()
在JDK7中有所改进,substring()方法在堆中真正的创建了一个新的数组,当原字符数组没有被引用后就被GC回收了.因此避免了上述问题.
1
2
3
4
5
6
7
8
9
10
11
|
//JDK 7 public String( char value[], int offset, int count) {
//check boundary
this .value = Arrays.copyOfRange(value, offset, offset + count);
} public String substring( int beginIndex, int endIndex) {
//check boundary
int subLen = endIndex - beginIndex;
return new String(value, beginIndex, subLen);
} |
相关推荐
### 如何解决Java内存泄漏 #### 1. 背景 Java凭借其垃圾回收机制大大简化了内存管理,使得开发者无需手动管理内存的释放,从而提升了开发效率。然而,这种自动化管理也可能成为一把双刃剑,特别是当开发人员忽视...
Java内存管理是开发Java应用程序时的关键环节,内存泄露和溢出问题可能导致系统性能下降,甚至导致服务崩溃。本文将深入探讨如何检测和分析Java内存泄露与溢出,并介绍一种常用的工具——Memory Analyzer(MAT)。 ...
Java内存泄漏是一个严重的问题,它会导致程序性能下降,甚至可能导致应用程序崩溃。为了有效地诊断和解决这类问题,开发者需要借助特定的分析工具。本篇将详细探讨Java内存泄漏及其相关的分析工具。 内存泄漏是指...
Java内存泄漏分析是一个关键的系统优化任务,尤其是在大型企业级应用中,长期运行的系统可能会因为内存泄漏导致性能下降甚至服务中断。"JAVA内存泄漏分析工具"正是一款用于解决此类问题的专业工具,它能帮助开发者...
"Java内存泄露_JVM监控工具介绍" Java内存泄露是Java开发中常见的一种问题,发生内存泄露可能会导致Java应用程序崩溃或性能下降。在Java中,内存泄露的原因非常多样,例如,静态变量、循环引用、数据库连接池、...
Java内存泄漏问题追踪 在Java编程中,内存泄漏是一个严重的问题,它会导致程序性能下降,甚至可能导致应用程序崩溃。内存泄漏是指程序在申请内存后,无法释放已不再使用的内存空间,随着时间推移,系统可用内存逐渐...
4. Native内存泄漏:Java应用可能使用JNI(Java Native Interface)与C/C++代码交互,若C/C++部分存在内存泄漏,也会间接导致Java内存泄漏。 解决内存泄漏的方法主要包括: 1. 使用工具监控:通过工具如VisualVM、...
Java内存泄露是一个严重的问题,它可能导致程序性能下降,甚至导致应用程序崩溃。Eclipse Memory Analyzer(MAT)是一款强大的Java内存分析工具,特别适用于检测和解决内存泄露。标题提到的"java内存泄露分析工具 ...
### Java内存泄漏详解 #### JVM内存管理概览 在探讨Java内存泄漏之前,我们先简要回顾一下JVM(Java虚拟机)的基本架构及其内存管理机制。这有助于更好地理解内存泄漏的发生原因及其解决方法。 ##### 类装载子...
### Java内存泄漏解决方案详解 #### 一、Java内存泄漏概述 在Java开发过程中,经常会遇到内存泄漏的问题,尤其是在长时间运行的应用程序中更为常见。本文将详细介绍如何解决Java内存泄漏问题,帮助开发者更好地...
Java内存泄露检测是Java开发中一个关键的议题,因为它直接影响到程序的稳定性和资源效率。内存泄露是指程序中已分配的内存无法被正确地释放,从而导致系统资源的浪费和可能导致程序性能下降甚至崩溃。 首先,理解...
检测Java内存泄漏的方法包括使用JVM提供的工具,如VisualVM、JProfiler等,它们可以监测堆内存使用情况,定位对象生命周期,找出长时间存活但不再使用的对象。此外,还可以通过代码审查、单元测试、压力测试等手段...
Java内存泄露的示例代码的知识点总结 Java内存泄露是指Java应用程序中由于某些原因导致的内存不能被正确释放,导致JVM OutOfMemory的错误。本文通过一个Demo来介绍ThreadLocal和ClassLoader导致内存泄露最终OutOf...
什么是内存泄漏?造成内存泄漏的原因?如何解决内存泄漏?以及如何避免内存泄漏等。。。
### 关于Java内存泄漏 #### 一、Java内存管理机制 Java的一大特色在于其自动化的内存管理机制,这主要依赖于垃圾收集器(Garbage Collection, GC)来自动完成对象的内存分配与回收。尽管这一特性极大地减轻了...
java内存泄露定位与分析
Java内存泄露是一个严重的问题,它可能导致系统性能下降,甚至服务崩溃。分析和解决这些问题需要深入理解Java内存模型、垃圾收集机制以及JVM优化策略。以下是对这个主题的详细阐述: 1. **Java内存模型** Java内存...
Java内存泄漏问题是一个重要的主题,尤其对于大型的J2EE应用程序而言,理解并避免内存泄漏至关重要。虽然Java的垃圾收集机制能自动管理内存,但并不意味着程序员可以完全忽视内存管理。以下是一些关于Java内存泄漏的...