[quoted text, click to view] devdude wrote:
> Barry, thanks for the response, see inline.
>
> On Apr 21, 6:35 am, Barry Kelly <barry.j.ke...@gmail.com> wrote:
> > It sounds like you need a more aggressive cache expiration policy. As
> As mentioned, this was stress testing so I wanted to push the cache to
> the size limit and see how it would respond while scavenging.
Sure. All I was saying is that if stress testing shows problems, then
perhaps it indicates a lax expiration policy.
[quoted text, click to view] > > When dealing with large amounts of data, I find GC is often not the best
> > way to go. I end up writing manual allocators for byte arrays. This
> > makes most sense when the data you're caching is in fact a byte array,
> > or other value-typed array, of course. However, I still allocate those
> > byte arrays from the .NET GC. It's just that they're all over the large
> > block limit (80K or so), and I carefully recycle them through a pool.
>
> Can you explain this further? Do you mean you alloc a huge block of
> memory to insure it sits in the LOH and suballocate from there (ala
> your own memory management on the managed heap?)
No, though I have done something like that too, and used a kind of
ArraySlice<T> handle to work with buffers. I worked strictly with byte
arrays, though the code was generic and would have made sense with any
value type. The primary use for the byte arrays in my case was as
buffers for I/O. However, if you implement your cache store such that it
can be processed in a streaming fashion, then you can rely on the LOH
and manual management for memory and GC generation 0 for efficient
cleanup of temporary structures.
[quoted text, click to view] > If so, how does the
> suballocations look? Does C# have a placement new like C++?
No. The CLR doesn't support directly mixing managed and unmanaged
memory. Managed->unmanaged needs to be an opaque pointer, usually
IntPtr, while unmanaged->managed needs to be a GC root, e.g. GCHandle,
or gcroot<> in C++.
[quoted text, click to view] > > BTW, you can still do manual memory allocation in C#, using the Marshal
> > class or by writing the PInvoke signatures yourself. However, I'd take a
> > closer look at your expiration policy before I'd go off and try and
> > reimplement a cache.
>
> How does one serialize/deserialize managed objects onto the native
> heap if these managed objects can be derived from a common base (e.g.
> CacheItem<-MyCacheItem, CacheItem<-MyOtherCacheItem)?
Some ideas: using Stream wrapped around one of the aforementioned LOH
buffers, use ordinary .NET serialization to iterate through structures,
a bit like IDataReader or XmlReader etc. It seems to me that the better
performance you want to get, the more specific your solution becomes to
your problem set.
[quoted text, click to view] > I'm (also)
> wondering if memory fragmentation will start occurring in the native
> heap?
If you allocate memory manually or semi-manually (e.g. GC LOH recycled
buffers), you can implement it such that you don't need to worry about
fragmentation, given some constraints. For example, emulate generations
by having a list of stack-oriented allocators which trivially deallocate
by changing the top location. Alternatively, use circular buffers, etc.
-- Barry
--