《Effective java》读书笔记——过期引用

来源:互联网 发布:网络推广部门口号 编辑:程序博客网 时间:2024/06/05 10:03
过期引用,指永远也不会再被解除的引用。
栈的pop函数的一般实现:
<span style="font-size:18px;">     public Object pop() {            if ( size == 0)                 throw new EmptyStackException();            // 上面的过期已用没有清除,所以会发生内存泄露            return elements [--size ];     }</span>

由于pop只是将栈顶标识下移,而并没有释放栈中相应位置的对象,所以栈中有效范围外的对象仍在存在,并不会被Gc释放,所以会造成内存泄露。要解决这种问题,需要在每次对象引用过期时,清空引用
<span style="font-size:18px;">     public Object pop() {            if ( size == 0)                 throw new EmptyStackException();            elements[ size]= null;            return elements[-- size];     }</span>

清空对象引用应该是一种例外,而不是一种规范行为。只在需要的地方清空过期引用。一般而言,只要类是自己管理内存,程序员就应该警惕内存泄露问题
内存泄露Example:
(1)栈就是其中的一个例子,栈管理一个内存数组,其中包括只有栈能识别的有效区域数据和无效数据,而整个内存数组的所有引用对于Gc来讲都是等效的,所以需要程序员告诉Gc哪些数据是不重要的,便于Gc清理。
(2)缓存:缓存项随着时间的推移需要清理掉没用的项(只要该键值没有对应的外部引用时就清理掉),实现方式有三种:一是通过Gc自动清理弱引用的机制,WeakHashMap(键对象间接的存储为一个弱引用的指示对象),当某个键不再正常使用时将自动移除其条目。更精确地说,对于一个给定的键,其映射的存在并不阻止垃圾回收器对该键的丢弃,这就使该键成为可终止的,被终止,然后被回收。二是在给缓存添加新条目的时候顺便进行清理,LinkedHashMap就是利用removeEldestEntry()方法实现的;三是自定义一个后台线程(Timer或者ScheduledThreadPoolExector)来完成。
(3)监听器和回调:如果用户不断注册回调,却没有显示的取消回调就会造成内存泄露。最好只保存回调的弱引用,如将它们保存成WeakHashMap中的键。对于该段话的理解如下:来源(http://stackoverflow.com/questions/2859464/how-to-avoid-memory-leaks-in-callback)
To illustrate the concept with a quick (crude) example, consider the following:
 
                 public interface ChangeHandler {                    public void handleChange();                 }                 public class FileMonitor {                    private File file;                    private Set< ChangeHandler> handlers = newHashSet<ChangeHandler>();                    public FileMonitor( File file) {                        this .file = file;                    }                    public voidregisterChangeHandler(ChangeHandler handler) {                        this .handlers.add(handler);                    }                    public voidunregisterChangeHandler(ChangeHandler handler) {                        this .handlers.remove(handler);                    }                    ...                }

 If a client class then uses this FileMonitor APIthey might do this: 
                public class MyClass {                    File myFile = new File( ...);                    FileMonitor monitor = new FileMonitor(myFile );                    public void something() {                        ...                        ChangeHandler myHandler = getChangeHandler();                        monitor.registerChangeHandler(myHandler);                        ...                    }                }

     If the author of the MyClass then forgets to call unregisterChangeHandler() when it's done with the handler, the FileMonitor' s HashSet will forever reference the instance that was registered, causing it to remain in memory until the FileMonitor is destroyed or the application quits.

     To prevent this, Bloch is suggesting using a weak-referencing collection instead of the HashSet, so that if your instance of MyClass isdestroyed, the reference will be removed from the monitor's collection.

     You might replace the HashSet in FileMonitor with a WeakHashMap and use the handlers as the keys, since the latter will automatically remove the  handler from the collection when all other references to the object are gone .
           





















0 0
原创粉丝点击