下面这段程序存在一个“内存泄漏”。在极端的情况下,会导致磁盘交换(Disk Paging),甚至导致程序失败(OutOfMemoryError)。
那么哪里引起的内存泄漏呢?
如果一个栈先是增长,然后再收缩,那么从栈中弹出来的对象讲不会被当做垃圾回收,即使使用的栈程序不再引用这些对象。
这是因为,栈内部维护着对这些对象的过期引用(obsolete reference)。过期引用是指,永远也不会再被接触的引用。
demo:
- // Can you spot the "memory leak"?
- import java.util.*;
- public class Stack {
- private Object[] elements;
- private int size = 0;
- private static final int DEFAULT_INITIAL_CAPACITY = 16;
- public Stack() {
- elements = new Object[DEFAULT_INITIAL_CAPACITY];
- }
- public void push(Object e) {
- ensureCapacity();
- elements[size++] = e;
- }
- public Object pop() {
- if (size == 0)
- throw new EmptyStackException();
- return elements[--size];
- }
- /**
- * Ensure space for at least one more element, roughly
- * doubling the capacity each time the array needs to grow.
- */
- private void ensureCapacity() {
- if (elements.length == size)
- elements = Arrays.copyOf(elements, 2 * size + 1);
- }
- }
修复的方法:
一旦对象引用已经过期,只需清空这些引用即可。
- public Object pop() {
- if (size == 0)
- throw new EmptyStackException();
- Object result = elements[--size];
- elements[size] = null; //Eliminate obsolete reference
- return result;
- }
当然也没必要谨慎的将所有不用的东西设置为null。
清空对象引用应该是一种例外,而不是一种规范行为。
消除过期引用最好的方法是让包含该引用的变量结束其生命周期。
那么,合适应该清空引用呢?
问题在于,Stack类自己管理内存。存储池包含了elements数组的元素。数组活动区域中的元素是已分配的,而数组其余部分的元素则是自由的。
但是对于垃圾回收器而言,elements数组中的所有对象引用都同等有效。
一旦数组元素变成了非活动部分的一部分,程序员就收工清空这些数组元素。
只要类是自己管理内存,程序员就应该警惕内存泄漏问题。
内存泄漏的另一个常见来源是缓存。
LinkedHashMap类的removeEldestEntry(Map.Entry<K,V> eldest) 此方法非常有用:它允许映射通过删除旧条目来减少内存损耗。
内存泄漏的第三个常见来源是监听器和其他回调。
如果你实现了一个API,客户端在这个API中注册回调,却没有显示的取消注册,那么除非你采取某些动作,否则他们就会积聚。
最佳方法是只保存他们的弱引用(weak reference),例如,只将他们保存为WeakHashMap中键。
可借助于Heap剖析工具(Heap Profiler)发现内存泄漏问题。
相关推荐
- Item6:消除过期对象引用,避免内存泄漏。及时将不再使用的对象设置为null,使其可以被垃圾收集器回收。 3. **处理对象生命周期** - Item7:Java中的finalizers用于清理对象资源,但不应依赖其执行,因为它们...
消除过期的对象引用 消除过期引用是非常重要的,不仅可以减少内存占用,还可以避免对象泄露和内存溢出。消除过期引用可以使用多种方法,例如,使用 WeakReference 或 SoftReference,或者使用 finalize() 方法来...
在《Effective Java 2nd Edition》中,第6条“消除过期的对象引用”提到,虽然Java有垃圾回收机制,但是只要是自己管理的内存,应该警惕内存泄露的问题,例如的对象池、缓存中的过期对象都有可能引发内存泄露的问题...
2. **清除浏览器缓存**:浏览器缓存中可能存在损坏的文件或过期的数据,清理缓存有助于消除这些潜在的问题。 3. **检查病毒感染**:病毒或恶意软件可能干扰正常的脚本执行,使用反病毒软件进行全面扫描是必要的。 4....
6. **条目6:消除过期的对象引用(Eliminate Unused Object References)** 过期的对象引用可能导致内存泄漏,确保及时释放不再使用的对象。 7. **条目7:覆盖equals时总要覆盖hashCode(Override equals() and ...
- **避免创建重复对象**:消除对过期对象的引用,一旦对象不再需要,应立即清除资源和引用,防止内存泄漏。 2. **对象定义** - **equals方法的重载**:当类需要实现逻辑等价测试时,应重载equals方法,确保与...
LeakExample程序旨在演示如何定位一个过期集合引用所导致的Java堆中整个对象树的游离问题。通过本教程,开发者将学会如何使用JProbe来识别代码中的游离对象,并采取措施修复这些问题。 ##### 3.2 操作步骤 ###### ...
例如,如果程序中存在对不再需要的对象的引用,那么这些对象将不会被垃圾回收器清理掉,从而导致内存泄漏。 #### 典型的内存泄漏原因 ##### 1. 全局集合的不当管理 在大型应用中,常常需要使用全局集合(例如JNDI...
1. 右值引用:这是实现移动语义的关键,它允许函数参数捕获临时对象或即将过期的对象。用`&&`符号表示,如`T&& obj`。 2. 移动构造函数:当一个新对象通过另一个即将销毁的对象创建时,移动构造函数会被调用。它将...
**解决方案**: 消除命名空间内的命名冲突。 #### 错误 CS0105 **描述**: 使用了已过期的类型。 **解决方案**: 替换为有效的类型。 #### 错误 CS0106 **描述**: 属性值不在当前范围内有效。 **解决方案**: 确认属性...
- **实际应用**:利用MySQL事件可以实现定时任务的自动化处理,如定期备份数据、清理过期记录等。 #### 4. 软件分类 - **知识点说明**:软件可以分为应用软件、系统软件和支持软件(或工具软件)。其中,教务管理...
b+ v+ T d/ R在活动目录中每个对象都有一个标识名,标识名确定了对象所在的域和可以找到对象的完整路径。比如,典型的标识名包括: ) v( ^# h2 Q% P ) k( @' h3 e4 k* G+ s" i7 `CN=TOM,OU=Manager,DC=Tech,DC=...
引用计数法............................................................................................................................................... 26 2.4.1.2. 可达性分析..........................