Ayende @ Rahien

Hi!
My name is Ayende Rahien
Founder of Hibernating Rhinos LTD and RavenDB.
You can reach me by phone or email:

ayende@ayende.com

+972 52-548-6969

@

Posts: 5,947 | Comments: 44,541

filter by tags archive

Design patterns in the test of timeFlyweight


A flyweight is an object that minimizes memory use by sharing as much data as possible with other similar objects; it is a way to use objects in large numbers when a simple repeated representation would use an unacceptable amount of memory.

More about this pattern.

On the face of it, this patterns looks very much like something from the old ages. And indeed, most implementations of Flyweight are actually focused deeply on low memory conditions. I would actually argue that you need to consider very carefully when you want to do that.

That said, it is actually used fairly often in high performance places. In the .NET framework, the notion of string interning is one way to get flywieghts (although the problem is that you need to start with a string to get the intern string sort of mess things up). In both the profilers and in RavenDB, we have used variations on the Flyweight pattern.

In the profiler, we are mostly dealing with parsing data from the profiled system, and that means doing a lot of reading from a stream and creating objects. That created an unacceptable memory pressure on the system. We implemented a fairly complex system where we can read from the stream into a buffer, then get or create the string from it. We contributed the implementation back to the Protocol Buffers project. You can see the code here.

In RavenDB, we deal a lot with documents, and many times we find it useful to be caching a document. The problem with doing that is that you need to return something from the cache, which means that you have to return something mutable. Instead of copying all of the data all the time, the internal RavenDB data structures supports copy-on-write semantics, which means that we can easily create clones at basically no cost.

Recommendation: If you are in a perf optimization mode, and you worry about memory pressure, consider using this. Otherwise, like all optimizations, it should be left alone until you have profiler results that says you should consider this.

More posts in "Design patterns in the test of time" series:

  1. (21 Jan 2013) Mediator
  2. (18 Jan 2013) Iterator
  3. (17 Jan 2013) Interpreter
  4. (21 Nov 2012) Command, Redux
  5. (19 Nov 2012) Command
  6. (16 Nov 2012) Chain of responsibility
  7. (15 Nov 2012) Proxy
  8. (14 Nov 2012) Flyweight
  9. (09 Nov 2012) Façade
  10. (07 Nov 2012) Decorator
  11. (05 Nov 2012) Composite
  12. (02 Nov 2012) Bridge
  13. (01 Nov 2012) Adapter
  14. (31 Oct 2012) Singleton
  15. (29 Oct 2012) Prototype
  16. (26 Oct 2012) Factory Method
  17. (25 Oct 2012) Builder
  18. (24 Oct 2012) A modern alternative to Abstract Factory–filtered dependencies
  19. (23 Oct 2012) Abstract Factory

Comments

Mark Seemann

Another example of flyweight is the Singleton lifestyle that many DI Containers (e.g. Castle Windsor) offer.

Jason Meckley

@Mark, no singleton is just that a singleton, flyweight is something else entirely. It's also comparing apples and oranges. IoC Containers are an entire framework that utilizes multiple patterns. the inner workings of an IoC may utilize flyweight, but that is agnostic about how the IoC is consumed by the application itself. From the calling codes point of view an IoC container acts as a registry or factory.

sukru

I used this for a text-mining project, after exhausting first the 32-bits heap, then (after targeting 64-bits mode) the virtual memory. It really sped up the calculations by at least 10-fold (by not trashing items to swap).

James McKay

The thing about the Flyweight pattern is that it's pretty easy to understand, has a low cost to implementing it, doesn't tend to suffer much abuse, and usually gives significant benefits in terms of memory use in particular. I could also foresee some situations where it could be quite tricky to retro-fit it at a later date if necessary. With that in mind, I'd have thought that it would be good to keep it in mind as a possibility when first writing your code, rather than waiting till your profiler demands it.

I personally think the oft-quoted dictum, "Premature optimisation is the root of all evil" should be taken with a pinch of salt. A failure to optimise your code is actually a form of technical debt, and an optimisation is only premature if the size of that debt is small compared to the cost of implementing it, or compared to other performance bottlenecks elsewhere. I'm not entirely convinced that this is generally the case in situations where a Flyweight is up for consideration.

Mark Seemann

@Jason Meckley, notice that I wrote "Singleton lifestyle" - not "Singleton pattern". It's not the same thing.

Comment preview

Comments have been closed on this topic.

FUTURE POSTS

No future posts left, oh my!

RECENT SERIES

  1. RavenDB Sharding (3):
    22 May 2015 - Adding a new shard to an existing cluster, splitting the shard
  2. The RavenDB Comic Strip (2):
    20 May 2015 - Part II – a team in trouble!
  3. Challenge (45):
    28 Apr 2015 - What is the meaning of this change?
  4. Interview question (2):
    30 Mar 2015 - fix the index
  5. Excerpts from the RavenDB Performance team report (20):
    20 Feb 2015 - Optimizing Compare – The circle of life (a post-mortem)
View all series

RECENT COMMENTS

Syndication

Main feed Feed Stats
Comments feed   Comments Feed Stats