I'm wondering if it's better to use one global instance of NSCache or several ones for each component that need it.
For example, I have several view subclasses that draw content into images and cache them to avoid regenerating them all the time.
Is it better to have one instance of NSCache per class or just one centralized NSCache for the whole app?
I don't mean one cache per instance of an object! I'm talking about one instance of NSCache for each class.
It obviously depends, but I would generally vote for one cache for each type of cached object. That way, you can have different countLimit values for each, e.g. to specify things like "keep the 50 most recently rendered thumbnails", "keep the 5 most recently downloaded large images", "keep the 10 most recently downloaded PDFs", etc.
For really computationally expensive tasks, I also employ two tier caching, NSCache for optimal performance, and saving to a temporary/cache directory in the local file system to avoid costly download cycles while not consuming RAM.
If cached items might be shared across components, you might as well have a unified cache - lookups won't be significantly more expensive and you at least have a chance of reducing redundant copies of your cached objects.
But if the cached items are unique per component, mixing them in a cache is pointless and from a code readability perspective likely confusing. Keep the caches separate, in that case. That also lets you more precisely control them - e.g. you could evict more aggressively in caches from components not being immediately used.
Related
Problem: I'm implementing aplication where user is dowloading lots of objects in xml. To reduce peak memory footprint I want to parse data to Core Data and then use batching to display them in table view. I don't want them to be saved anyhow because objects will be changing everyday but I want to let user choose its favourites object and then save them. Favourites will be displayed in different table view.
Solutions I'm thinking about:
Create two NSManagedObjectContext (one main and one tmp). Parse objects to tmp, if its marked as favourite copy object to main and save it from there.
Forget about memory and keep data in some array and save only choosen ones.
Save all using one NSManagedObjectContext and before application will terminate delete unmarket as favourites.
Any hint here would be nice. Also some code sample code with solution one because I'm new to Core Data and I may have problems. I've been looking for suitable solution for two days now.
I would suggest you forget about optimizing the memory footprint unless/until you have some hard evidence showing that this will in fact be needed. But of course it depends on what "lots of objects in xml" means exactly.
I am assuming you are not downloading millions of XML documents just to throw them away again when the application finishes (because that would be a serious waste of network resources). In contrast, an array with a few hundred or even a few thousand small XML-like data structures would most likely be nothing to worry about as far as memory is concerned.
That being said, if you would need to save both temporary and persistent data with Core Data after all, I would go for a single NSManagedObjectContext with two entities rather than two separate contexts. Or you could even have a single entity and mark certain instances as temporary data. Managing two different contexts means additional overhead while I don't really see any advantages to that approach.
There are so many functions like
1. NSDefaultMallocZone()
2. NSCreateZone();
3. NSRecycleZone();
4. NSSetZoneName();
5. NSZoneMalloc();
and many more related to NSZone
What does NSZone means, where to use these functions and when?
What are the advantages of initWithZone: and how to use in my iphone app?
NSZone is Apple's way of optimizing
object allocation and freeing. NSZone
is not an object; it is an opaque
C-struct storing information about how
memory should be handled for a set of
objects.
One rarely needs to worry about
handling your own zones in
applications; Cocoa handles it
transparently. A default NSZone is
created on startup and all objects
default to being allocated there. So
why would you want to use your own?
If you are mass-allocating hundreds of
cheap objects, you may find the cost
of actually allocating space for them
becomes significant. Because the
standard zone is used all the time, it
can become very patchy; deleted
objects can leave awkward gaps
throughout memory. The allocator for
the standard NSZone knows this, and it
tries to fill these gaps in preference
to grabbing more memory off the
system, but this can be costly in time
if the zone has grown quite large.
If you want to mass-allocate objects,
then, you can create your own zone and
tell it not to bother with finding
gaps to put new objects in. The
allocator can now jump to the end of
its allotted memory each time and
quickly assign memory to your new
objects, saving a lot of effort.
Allocators can save you time
elsewhere, too, as asking the OS for
more memory, which a zone needs to do
whenever it fills up, is another
costly operation if it's done a lot.
Much quicker is to ask for huge chunks
of memory at a time, and you can tell
your NSZone what to do here as well.
Rumor has it that NSZone could save
you deallocation time in the Good Old
Days, too, with a method that simply
chucks away all the allotted memory
without bothering to call
deallocators. If a set of objects is
self-contained, this could save a lot
of time, as you can chuck them all
away at once without tediously
deallocating them all. Alas, there
appears to be no sign of this godsend
in the current documentation; the
single NSZone method (NSRecycleZone?)
carefully puts all the objects in a
zone neatly on the default NSZone. Not
exactly a huge time-saver.
So, in summary, zones save you time in
mass allocations. But only if
programmers know how to use them!
From CocoaDev
I am trying to understand what would be the need to go with a solution like memcached. It may seem like a silly question - but what does it bring to the table if all I need is to cache objects? Won't a simple hashmap do ?
Quoting from the memcache web site, memcache is…
Free & open source, high-performance,
distributed memory object caching
system, generic in nature, but
intended for use in speeding up
dynamic web applications by
alleviating database load.
Memcached is an in-memory key-value
store for small chunks of arbitrary
data (strings, objects) from results
of database calls, API calls, or page
rendering. Memcached is simple yet
powerful. Its simple design promotes
quick deployment, ease of development,
and solves many problems facing large
data caches. Its API is available for
most popular languages.
At heart it is a simple Key/Value
store
A key word here is distributed. In general, quoting from the memcache site again,
Memcached servers are generally
unaware of each other. There is no
crosstalk, no syncronization, no
broadcasting. The lack of
interconnections means adding more
servers will usually add more capacity
as you expect. There might be
exceptions to this rule, but they are
exceptions and carefully regarded.
I would highly recommend reading the detailed description of memcache.
Where are you going to put this hashmap? That's what it's doing for you. Any structure you implement on PHP is only there until the request ends. If you throw stuff in a persistent cache, you can fetch it back out for other requests, instead of rebuilding the data.
I know that this question is rather old, but in addition to being able to share a cache across multiple servers, there is also another aspect that is not mentioned in other answers and is the values expiration.
If you store the values in a HashMap, and that HashMap is bound to the Application context, it will keep growing in size, unless you expire items in some ways. Memcached expires object lazily for maximum performance.
When an item is added to the memcache, it can have an expiration time, for instance 600 seconds. After the object is expired it will just remain there, but if another object asks for it, it will purge it and return null.
Similarly, when memcached memory is full, it will look for the first expired item of adequate size and expire it to make room for the new item. Lastly, it can also happen that the cache is full and there isn't any item to expire, in which case it will replace the least used items.
Using a fully flagded cache system usually allow you to replicate the cache on many servers, or just scale to many server just to scale a lot of parallel requestes, all this remaining acceptable fast in term of reply.
There is an (old) article that compares different caching systems used by php:
https://www.percona.com/blog/2006/08/09/cache-performance-comparison/
Basically, file caching is faster than memcached.
So to answer the question, I believe you would have better performances using a file based cache system.
Here are the results from the tests of the article:
Cache Type Cache Gets/sec
Array Cache 365000
APC Cache 98000
File Cache 27000
Memcached Cache (TCP/IP) 12200
MySQL Query Cache (TCP/IP) 9900
MySQL Query Cache (Unix Socket) 13500
Selecting from table (TCP/IP) 5100
Selecting from table (Unix Socket) 7400
Are RDBOC objects cached through different processes? I'm thining of running it in mod-perl, and it would factor into things, even though it would mostly be used on things that don't change (much).
Also, do relationships referencing RDBOCs use the cache when it should intuitively?
Rose::DB::Object::Cached caches objects in plain-old (non-shared) memory. Under mod_perl, this means that each apache process has its own cache. You could, however, cache your objects on server startup. All of those cached objects would then be shared with each apache child process. This is most useful for read-only objects that you don't ever expect to change for the life of the server.
For more flexible caching options, check out Rose::DBx::Object::Cached::CHI.
As for your second question, Rose::DB::Object::Cached only reads from and writes to the cache on load() and save(). Most relationship methods use Manager queries to get objects and so will not read from the Rose::DB::Object::Cached cache.
I use memcached to store the integer result of a complex calculation. I've got hundreds of integer objects that I could cache! Should I cache them under a single key in a more complex object or should I use hundreds of different keys for the objects? (the objects I'm caching do not need to be invalidated more than once a day)
I would say lots of little keys. This way you can get the exact result you want in 1 call with minimal serialization effort.
If you store it in another object (an array for example) you will have to fetch the array from cache and then fetch the item you actually want again from that array, plus you have the overhead of serializing/deserializing the whole complex object again. Depending on your language of choice this might mean manually writing a serialization/deserialization function from scratch.
I wrote somewhat large analysis at http://dammit.lt/2008/12/25/memcached-for-small-objects/ - it outlines how to optimize memcached for small object storage - it may shed quite some light on the issue.
It depends on your application. While memcached is very fast, it does require some request transmission and memory lookup time per request. Those numbers increase depending on whether or not the server is on the local machine (localhost), on the local network, or across a wide area. The size of your cache generally doesn't affect the lookup speed.
So, if your application is using MANY objects per processing unit (per request, method, or what-have-you), then it's generally better to define your cache in a way which lowers total number of hits to the cache while at the same time trying not to duplicate cache data. Like everything else, it's a balance.
i.e. If you have a web request which pulls a list of blog posts, it would be more beneficial to cache the entire object list as one memcached key, rather than (and this is a somewhat bad example, obviously) caching an array of cache keys for that list, which relate to individually memcached objects.
The less processing you have to do of the cached values, the better. So why not just dump them into the cache individually?
I would say you should store values individually and use some kind of helper class to retrieve values with multiget and generate a complex dataobject for you.
It depends on what are those numbers. If you could, for example, group them in ranges, then you could optimize the storage. If you could hash them, into a map, or hashtable and store that map serialized in memcached would be good to.
Anyway, you can save many little keys, just make sure you configure the slabs to have chunks with small size, so you will not waste memory space.