예제 #1
0
 internal GCHandleContainer()
 {
     // Allocations of pinned gc handles done only once during the lifetime of a thread
     _thisPtrHandle          = UnsafeGCHandle.Alloc(null, GCHandleType.Pinned);
     _dynamicInvokeArgHandle = UnsafeGCHandle.Alloc(null, GCHandleType.Pinned);
     _returnObjectHandle     = UnsafeGCHandle.Alloc(null, GCHandleType.Pinned);
 }
예제 #2
0
            private static Entry[] ResizeCacheForNewEntryAsNecessary()
            {
                Entry[] cache = s_cache;

                int entries = s_entries++;

                // If the cache has spare space, we are done
                if (2 * entries < cache.Length)
                {
                    if (s_roundRobinFlushing)
                    {
                        cache[2 * entries]     = null;
                        cache[2 * entries + 1] = null;
                    }
                    return(cache);
                }

                //
                // Now, we have cache that is overflowing with results. We need to decide whether to resize it or start
                // flushing the old entries instead
                //

                // Start over counting the entries
                s_entries = 0;

                // See how long it has been since the last time the cache was overflowing
                long tickCount = InternalCalls.PalGetTickCount64();
                int  tickCountSinceLastOverflow = (int)(tickCount - s_tickCountOfLastOverflow);

                s_tickCountOfLastOverflow = tickCount;

                bool shrinkCache = false;
                bool growCache   = false;

                if (cache.Length < DefaultCacheSize)
                {
                    // If the cache have not reached the default size, just grow it without thinking about it much
                    growCache = true;
                }
                else
                {
                    if (tickCountSinceLastOverflow < cache.Length)
                    {
                        // We 'overflow' when 2*entries == cache.Length, so we have cache.Length / 2 entries that were
                        // filled in tickCountSinceLastOverflow ms, which is 2ms/entry

                        // If the fill rate of the cache is faster than ~2ms per entry, grow it
                        if (cache.Length < MaximumCacheSize)
                        {
                            growCache = true;
                        }
                    }
                    else
                    if (tickCountSinceLastOverflow > cache.Length * 16)
                    {
                        // We 'overflow' when 2*entries == cache.Length, so we have ((cache.Length*16) / 2) entries that
                        // were filled in tickCountSinceLastOverflow ms, which is 32ms/entry

                        // If the fill rate of the cache is slower than 32ms per entry, shrink it
                        if (cache.Length > DefaultCacheSize)
                        {
                            shrinkCache = true;
                        }
                    }
                    // Otherwise, keep the current size and just keep flushing the entries round robin
                }

                Entry[] newCache = null;
                if (growCache || shrinkCache)
                {
                    try
                    {
                        newCache = new Entry[shrinkCache ? (cache.Length / 2) : (cache.Length * 2)];
                    }
                    catch (OutOfMemoryException)
                    {
                        // Failed to allocate a bigger/smaller cache.  That is fine, keep the old one.
                    }
                }

                if (newCache != null)
                {
                    s_roundRobinFlushing = false;

                    // Keep the reference to the old cache in a weak handle. We will try to use it to avoid hitting the
                    // cache miss path until the GC collects it.
                    if (s_previousCache.IsAllocated)
                    {
                        s_previousCache.Target = cache;
                    }
                    else
                    {
                        try
                        {
                            s_previousCache = UnsafeGCHandle.Alloc(cache, GCHandleType.Weak);
                        }
                        catch (OutOfMemoryException)
                        {
                            // Failed to allocate the handle to utilize the old cache, that is fine, we will just miss
                            // out on repopulating the new cache from the old cache.
                            s_previousCache = default(UnsafeGCHandle);
                        }
                    }

                    return(s_cache = newCache);
                }
                else
                {
                    s_roundRobinFlushing = true;
                    return(cache);
                }
            }