static extern bool GlobalMemoryStatusEx([In, Out] MEMORYSTATUSEX lpBuffer);
        //Add the feature string into list and get feature string id
        public long GetOrAddId(string strFeature)
        {
            while (ShrinkingLock == 1) { Thread.Sleep(5000); }

            //add item-adding lock
            Interlocked.Increment(ref AddLock);

            FeatureFreq newFFItem = new FeatureFreq();
            newFFItem.strFeature = strFeature;
            newFFItem.value = 1;
            if (sortedEndIndex > 0)
            {
                FeatureFreq ff = arrayFeatureFreq.BinarySearch(0, sortedEndIndex, newFFItem);
                if (ff != null)
                {
                    Interlocked.Increment(ref ff.value);
                    //free item-adding lock
                    Interlocked.Decrement(ref AddLock);
                    return GetId(strFeature);
                }
            }

            long oldValue = Interlocked.Increment(ref arrayFeatureFreqSize) - 1;
            arrayFeatureFreq[oldValue] = newFFItem;

            //free item-adding lock
            Interlocked.Decrement(ref AddLock);

            //Check whether shrink process should be started
            uint memoryLoad = 0;
            if (oldValue % 10000000 == 0)
            {
                MEMORYSTATUSEX msex = new MEMORYSTATUSEX();
                GlobalMemoryStatusEx(msex);
                memoryLoad = msex.dwMemoryLoad;
            }

            if (memoryLoad >= SHRINK_AVALI_MEM_LOAD)
            {
                if (Interlocked.CompareExchange(ref ShrinkingLock, 1, 0) == 0)
                {
                    //Double check whether shrink should be started
                    MEMORYSTATUSEX msex = new MEMORYSTATUSEX();
                    GlobalMemoryStatusEx(msex);
                    if (msex.dwMemoryLoad >= SHRINK_AVALI_MEM_LOAD)
                    {
                        while (AddLock != 0) { Thread.Sleep(1000); }

                        DateTime startDT = DateTime.Now;
                        Console.WriteLine("Begin to shrink [Feature Size: {0}]...", arrayFeatureFreqSize);
                        long newArrayFeatureFreqSize = Shrink(0, arrayFeatureFreqSize - 1, 0) + 1;

                        GlobalMemoryStatusEx(msex);
                        if (msex.dwMemoryLoad >= SHRINK_AVALI_MEM_LOAD - 1)
                        {
                            //Still have enough available memory, raise shrink threshold
                            SHRINK_AVALI_MEM_LOAD = msex.dwMemoryLoad + 1;
                            if (SHRINK_AVALI_MEM_LOAD >= 100)
                            {
                                //if use more than 100% memory, the performance will extremely reduce
                                SHRINK_AVALI_MEM_LOAD = 100;
                            }
                        }

                        arrayFeatureFreqSize = newArrayFeatureFreqSize;
                        TimeSpan ts = DateTime.Now - startDT;
                        Console.WriteLine("Shrink has been done!");
                        Console.WriteLine("[Feature Size:{0}, TimeSpan:{1}, Next Shrink Rate:{2}%]", arrayFeatureFreqSize, ts, SHRINK_AVALI_MEM_LOAD);
                    }

                    Interlocked.Decrement(ref ShrinkingLock);
                }
            }
            return GetId(strFeature);
        }