开发者

When observe pattern cause GC problems

In a GC enabled language, when observer subscribes to events of subject, actually subject got a reference of observer.

So before drop an observer, it must un-subscribes first. Other wise, because it's still referenced by subject, it wi开发者_开发知识库ll never be garbage collected.

Normally there are 3 solutions:

  1. Manually un-subscribes
  2. Weak Reference.

Both of them cause other problems.

So usually I don't like to use observer patterns, but I still can not find any replacement for that.

I mean, this pattern describes thing in such a natural way that You could hardly find anything better.

What do you think about it?


In this scenario, you can use finalize() in Java. finalize() is a bad idea when you have to release a resource (like a DB connection) because some outside system is affected. In your case, the object which installed the observer will be GC'd during the runtime of your app and then, finalize() will be called and it can unsubscribe the observer.

Not exactly what you want but someone must decide "it's okay to unsubscribe, now". That either happens when your subject goes away (but it should already kill all observers) or the object which installed the observer.

If your app terminates unexpectedly, well, it doesn't hurt that finalize() might not be called in this case.


If you want to remove an observer you should inform the publisher by unsubscribing, first, otherwise it will try to send out events and depending on how it is written, it could crash the app, quietly ignore the error or remove the observer. But, if you open something, close it; if you subscribe, unsubscribe.

The fact that you are not unsubscribing is a bad design, IMO. Don't blame the pattern for a poor implementation.

The observer pattern works well, but if you want to alleviate some of the issues, you could use AOP for the implementation: http://www.cin.ufpe.br/~sugarloafplop/final_articles/20_ObserverAspects.pdf


Consider the scenario of an object which counts how often some observable thing changes. There are two types of references to the object: (1) those by entities which are interested in the count; (2) those used by the observable thing(s) which aren't really interested in the the count, but need to update it. The entities which are interested in the count should hold a reference to an object which in turn holds a reference to the one that manages the count. The entities that will have to update the count but aren't really interested in it should just hold references to the second object.

If the first object holds a finalizer, it will be fired when the object goes out of scope. That could trigger the second object to unsubscribe, but it should probably not be unsubscribed directly. Unsubscription would probably require acquiring a lock, and finalizers should not wait on locks. Instead, the finalizer of the first object should probably add that object to a linked list maintained using Interlocked.CompareExchange, and some other thread should periodically poll that list for objects needing unsubscription.

Note, btw: If the first object holds a reference to second object, the latter would be guaranteed to exist when the finalizer for the first object runs, but it would not be guaranteed to be in any particular state. The cleanup thread should not try to do anything with it other than unsubscribe.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜