Java 消除过期的对象引用
内存泄漏的第一个常见来源是存在过期引用。
import java.util.Arrays;
import java.util.EmptyStackException; 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];
} private void ensureCapacity() {
if (elements.length == size) {
elements = Arrays.copyOf(elements, 2 * size + 1);
}
} public void push(Object e) {
ensureCapacity();
elements[size++] = e;
} public Object pop() {
if (size == 0) {
throw new EmptyStackException();
} return elements[--size];
} }
如果一个栈先是增长,然后再收缩,从栈中弹出来的对象不会被当作垃圾回收,即使使用栈的程序不再引用这些对象,它们也不会被回收。因为栈内部维护着对这些对象的过期引用(obsolete reference)。过期引用指永远也不会再被解除的引用。在本例中,在elements数组的“活动部分(active portion)”之外的任何引用都是过期的。活动部分指elements中下标小于size的那些元素。
如果一个对象引用被无意识地保留了,垃圾回收机制不仅不会回收这个对象,而且不会回收被这个对象所引用的所有其他对象。解决方法:一旦对象引用已经过期,只需清空这些引用即可。在本例中,只要一个元素被弹出栈,指向它的引用就过期了。修改如下:
public Object pop() {
if (size == 0) {
throw new EmptyStackException();
} Object result = elements[--size];
elements[size] = null; // 清空引用 return result;
}
清空过期引用的另一个好处是,如果它们以后又被错误地解除引用,程序会立即抛出NullPointerException异常,而不是悄悄地错误运行下去。尽快地检测出程序中的错误总是有益的。消除过期引用最好的方法是让包含该引用的变量结束其生命周期。如果在最紧凑的作用域范围内定义每一个变量(见第45条),这种情形会自然而然地发生。
只要类是自己管理内存,程序员就应该警惕内存泄漏问题。一旦元素被释放掉,该元素中包含的任何对象引用都应该被清空。
内存泄漏的第二个常见来源是缓存。
把对象引用放到缓存中,它就很容易被遗忘掉,从而使得它不再有用之后很长一段时间内仍然留在缓存中。用WeakHashMap代表缓存时,当缓存中的项过期之后,它们会被自动地删除。只有当缓存项的生命周期是由该键的外部引用而不是由值决定时,WeakHashMap才起作用。
随着时间的推移,缓存项会变得越来越没有价值,缓存应该时不时地清除掉没用的项。可以由一个后台线程(可能是Timer或者ScheduledThreadPoolExecutor)来完成,或者在给缓存添加新条目时进行清理。LinkedHashMap类可以通过它的removeEldestEntry方法来实现后者。对于更加复杂的缓存,必须直接使用java.lang.ref。
内存泄漏的第三个常见来源是监听器和其他回调。
如果客户端在自己实现的API中注册回调,却没有显式地取消注册,那么除非自己采取某些动作,否则它们就会积聚。确保回调立即被当作垃圾回收的最佳方法是只保存它们的弱引用(weak reference),例如,只将它们保存为WeakHashMap中的键。
往往只有通过仔细检查代码,或者借助于Heap剖析工具(Heap Profiler)才能发现内存泄露问题。
参考资料
《Effective Java 中文版 第2版》 第6条:消除过期的对象引用 P21-23
Java 消除过期的对象引用的更多相关文章
- Effective Java —— 消除过期的对象引用
本文参考 本篇文章参考自<Effective Java>第三版第七条"Eliminate obsolete object references" Memory leak ...
- Effective Java 第三版——7. 消除过期的对象引用
Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...
- 《Effective Java》 读书笔记(七)消除过期的对象引用
大概看了一遍这个小节,其实这种感觉体验最多的应该是C/C++程序,有多杀少个new就得有多个delete. 一直以为Java就不会存在这个问题,看来是我太年轻. 感觉<Effective Jav ...
- Effective Java (6) - 消除过期的对象引用
一.引言 很多人可能在想这么一个问题:Java有垃圾回收机制,那么还存在内存泄露吗?答案是肯定的,所谓的垃圾回收GC会自动管理内存的回收,而不需要程序员每次都手动释放内存,但是如果存在大量的临时对象在 ...
- Effective Java 之-----消除过期的对象引用
public class Stack { private Object[] elements; private int size = 0; private static final int DEFAU ...
- Item 6 消除过期的对象引用
过期对象引用没有清理掉,会导致内存泄漏.对于没有用到的对象引用,可以置空,这是一种做法.而最好的做法是,把保存对象引用的变量清理掉,多用局部变量. 什么是内存泄漏? 在Java中,对象的内存空间回 ...
- EffectiveJava(6)消除过期对象的引用
消除过期对象的引用 过期引用 – 在操作集合类的时候,未清理过期的对象引用(即:过期引用),常会导致内存泄露.从而报outOfmemory错误. 1.过期对象导致内存泄漏. 2.一旦对象引用过期,清除 ...
- Java中对象、对象引用、堆、栈、值传递以及引用传递的详解
Java中对象.对象引用.堆.栈.值传递以及引用传递的详解 1.对象和对象引用的差别: (1).对象: 万物皆对象.对象是类的实例. 在Java中new是用来在堆上创建对象用的. 一个对象能够被多个引 ...
- java cache过期策略两种实现,一个基于list轮询一个基于timer定时
最近项目要引入缓存机制,但是不想引入分布式的缓存框架,所以自己就写了一个轻量级的缓存实现,有两个版本,一个是通过timer实现其超时过期处理,另外一个是通过list轮询. 首先要了解下ja ...
随机推荐
- 十六进制的ASCII码 "\u6cf0\u56fd" 解码成unicode
转码方法: C#: string a = "\u6cf0\u56fd"; string b = Encoding.UTF8.GetString(Encoding.UTF8.GetB ...
- VMware搭建虚拟机服务器
一.需求点描述: 1.在有路由器的情况下,能够通过固定的外网IP访问路由器中某台实体机中运行的虚拟机. 2.能够通过外网IP访问该虚拟机中的ftp.远程连接.iis.tomcat等. 二.原理分析: ...
- [转] React风格的企业前端技术
亲爱的各位朋友们,大家下午好! 首先祝大家国庆节快乐! 很高兴可以在国庆前夕,可以为大家分享一下React风格的企业前端技术. 谈到前端,可能以前大家的第一感觉就是,前端嘛,无非就是做做页面切图,顶多 ...
- element-ui上传文件带token
template> <el-upload action="test" :headers="myHeaders"></el-upload& ...
- 背包的一些idea
题解: 给出n个物品,每次能使用l-r之间的物品,问能不能表示出k,m次询问 k<=100,m,n=1e5 想了线段树分治 发现是k^2(n+m)logn claris告诉我可以直接分治 我们对 ...
- MySQl 查询性能优化相关
0. 1.参考 提升网站访问速度的 SQL 查询优化技巧 缓存一切数据,读取内存而不是硬盘IO 如果你的服务器默认情况下没有使用MySQL查询缓存,那么你应该开启缓存.开启缓存意味着MySQL 会把所 ...
- nginx 设置自签名证书以及设置网址http强制转https访问
自签名证书可以在自己的内网环境或者非对外环境使用,保证通信安装 1.生产证书 直接使用脚本生产: 中途会提示书如1次域名和4次密码,把一下文件保存为sh文件,赋予x权限后 直接执行,根据提示输入. # ...
- plink命令
用plink远程登陆link主机执行脚本,但是无法执行sudo命令 完成后自己关闭 plink -l root 192.168.1.21 df -h plink.exe -ssh -p ...
- 场景/故事/story——寻物者发布消息场景、寻失主发布消息场景、消息展示场景、登录网站场景
1.背景:(1)典型用户:吴昭[主要] 尤迅[次要] 王丛[次要] 佑豪[次要](2)用户的需求/迫切需要解决的问题a.吴昭:经常在校园各个地方各个时间段,丢失物品需要寻找.b.吴昭:偶尔浏览一下最 ...
- 如何在不使用try语句的情况下查看文件是否存在
如果你要确定文件存在的话然后做些什么,那么使用try是最好不过的 如果您不打算立即打开文件,则可以使用os.path.isfile检查文件 如果path是现有常规文件,则返回true.对于相同的路径, ...