Java尽管采用自动的内存管理方式,但是仍然存在泄露的可能,我们知道JVM认为对象没有引用时,会把这个对象视为垃圾。
Java内存泄露就存在于,这个对象实际上已经不再需要,但是仍然存在引用,此时就会产生内存泄露。
其实java导致内存泄露的原因很明确:长生命周期的对象持有短生命周期对象的引用就很可能发生内存泄露,尽管短生命周期对象已经不再需要,但是因为长生命周期对象持有它的引用而导致不能被回收,这就是java中内存泄露的发生场景。作者在书中提到了3个场景:
1.流失监听器问题,在awt、swing编程中,给组件添加了事件监听器,这些组件的生命周期如果很长的话,监听器对象将不能被正确回收。 关于GUI编程我不是很熟悉,这一点存有疑问,因为显然你触发一个按钮的事件,当然是一直期待同样的行为发生,如果删除了监听器或者使用弱引用让JVM回收不符合业务逻辑和用户体验。
2.集合类,集合类仅仅有添加元素的方法,而没有相应的删除机制,导致内存被占用。这一点其实也不明确,这个集合类如果仅仅是局部变量,根本不会造成内存泄露,在方法栈退出后就没有引用了会被jvm正常回收。 而如果这个集合类是全局性的变量(比如类中的静态属性,全局性的map等),那么没有相应的删除机制,很可能导致集合所占用的内存只增不减,因此提供这样的删除机制或者定期清除策略非常必要。
3.单例模式。 不正确使用单例模式是引起内存泄露的一个常见问题,单例对象在被初始化后将在JVM的整个生命周期中存在(以静态变量的方式),如果单例对象持有外部对象的引用,那么这个外部对象将不能被jvm正常回收,导致内存泄露。
常见的内存泄露代码如下:
1.Stack的内存泄露
下面是Stack的Pop方法,pop方法的作用是弹出栈最上面的对象,并释放这个对象的内存。
下面的代码可以看到,只是返回了栈最上面的对象,但是由于数组仍然对对象存在引用,因此这个对象不会被GC回收
public Object pop(){
if( size == 0)
throw new EmptyStackException();
return elements[--size];
}
看看java.util.Stack中的实现,
public synchronized E pop() {
E obj;
int len = size();
obj = peek();
removeElementAt(len - 1);
return obj;
}
public synchronized void removeElementAt(int index) {
modCount++;
if (index >= elementCount) {
throw new ArrayIndexOutOfBoundsException(index + " >= " +
elementCount);
}
else if (index < 0) {
throw new ArrayIndexOutOfBoundsException(index);
}
int j = elementCount - index - 1;
if (j > 0) {
System.arraycopy(elementData, index + 1, elementData, index, j);
}
elementCount--;
elementData[elementCount] = null; /* to let gc do its work */
}
红色字体部分,实际上就是释放了数组对对象的引用,因而,避免了内存泄露。
2.
分享到:
相关推荐
在上述代码示例中,`Task`类继承自`TimerTask`,表示实际要执行的任务。`run()`方法包含了定时任务的具体逻辑。在`ConvergeDataServlet`的`init()`方法中,根据配置参数决定是否启动定时器,并设置初始延迟(delay *...
### 示例代码分析 #### 字符串编码长度示例 ```java public static void main(String[] args) throws Exception { String str = "中国"; System.out.println(str.getBytes("UTF-8").length); // 输出6 System....
但在示例代码中并未使用,而是用到了MySQL的驱动。 2. 对于MySQL,驱动类是`com.mysql.jdbc.Driver`。在`getConnection()`方法中,已经指定了这个驱动类,并尝试加载它。 加载驱动类后,使用`DriverManager.get...
总的来说,这份“Findbugs系列资源汇总”为Java开发者提供了一个全面了解和应用Findbugs的平台。通过Eclipse插件,我们可以方便地进行静态分析,而缺陷详解则为我们提供了深入理解Findbugs警告的途径。不断学习和...
9. 示例代码:在Java中,我们可以使用JDBC和Apache POI的简单示例代码如下: ```java import java.sql.*; import org.apache.poi.ss.usermodel.*; import org.apache.poi.xssf.usermodel.XSSFWorkbook; public ...
- **在执行测试用的过程中检测内存泄露**:检查内存泄漏问题。 - **通过运行一个应用程序生成功能测试用例**:基于实际应用生成测试案例。 - **创建并使用参数化测试用例**:使用参数化测试提高灵活性。 - **生成并...
- 示例代码: ```java Connection conn = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:AOOPLE", "scott", "tiger"); ``` - **执行SQL语句**:通过 `Connection` 对象创建 `Statement` ...
- **3.24 在执行测试用的过程中检测内存泄露** - **定义:** 在测试过程中监控内存使用情况。 - **作用:** 防止内存泄漏导致的问题。 - **使用方法:** JTest可以实时监测内存占用情况,并报告可疑的内存泄漏。 ...
- Java 文档生成工具: 用于从Java源代码生成API文档。 - Java 打包工具: 用于将Java程序打包成可执行文件或部署包。 ### VFP中创建子类或表单的限制 - **限制**: 在Visual FoxPro中创建子类或表单时,不能新建的...
- 自动化测试脚本:如Python、Java或JavaScript编写的测试代码。 - 测试报告:汇总测试结果,包括通过率、失败情况和建议。 - 测试框架配置文件:如JUnit配置文件或Selenium测试套件。 - 示例数据:用于测试的...
- **测试报告:** 汇总了测试结果、发现的问题、测试覆盖率等信息,用于评估软件的质量状态。 - 这三者之间紧密关联:测试计划指导测试用例的设计和执行;测试用例的结果被记录在测试报告中,用于评估测试进度和...