UML软件工程组织

内存优化之道:托管代码的失传内存优化技术的再发现
来源:VC知识库 原著:Erik Brown

Figure 1 .NET Value Types

System Type C# Type Managed Size in Bytes Default Unmanaged Size in Bytes
System.Boolean bool 1 4
System.Byte byte 1 1
System.Char char 2 1
System.Decimal decimal 16 16
System.Double double 8 8
System.Single float 4 4
System.Int16 short 2 2
System.Int32 int 4 4
System.Int64 long 8 8
System.SByte sbyte 1 1
System.UInt16 ushort 2 2
System.UInt32 uint 4 4
System.UInt64 ulong 8 8

Figure 2 AddressType
enum AddressType
{
  Home,
  Secondary,
  Office
}

class Address
{
  public bool IsPayTo;
  public AddressType 
    AddressType;
  public string Address1;
  public string Address2;
  public string City;
  public string State;
  public string Zip;
}

Figure 3 Reducing Type Size
enum AddressType : short
{
    Home, 
    Secondary, 
    Office
}

class Address
{
    byte _isPayTo;
    AddressType _addrType;
    string _address1;
    string _address2;
    string _city;
    string _state;
    string _zip;

    public bool IsPayTo
    {
        get { return (_isPayTo == 1); }
        set { _isPayTo = (byte)(value ? 1 : 0); }
    }

    public string State
    {
        get { return _state; }
        set
        {
            if (value == null) _state = null;
            else _state = String.Intern(value.ToUpper());
        }
    }

    public AddressType AddressType 
    {
        get { return _addrType; } set { _addrType = value; }
    }

    public string Address1
    {
        get { return _address1; } set { _address1 = value; }
    }

    public string Address2 
    {
        get { return _address2; } set { _address2 = value; }
    }
    
    public string City { ... }
    
    public string Zip { ... }
}

Figure 4 ObjectPool in .NET
public class ObjectPool
{
    // ObjectPool is implemented as a Singleton
    public static ObjectPool GetInstance() { ... }

    // Delegates used by the interface
    public delegate object CreateObject();
    public delegate void UseObject(object obj, object [] args);

    // Initiate pooling for the given type
    public void RegisterType(Type t, CreateObject createDelegate,
        short minPoolSize, short maxPoolSize, int creationTimeout) { ... }

    // Terminate pooling for the given type
    public void UnregisterType(Type t) { ... }

    // Get and release objects in the pool
    public object GetObject(Type t) { ... }
    public void ReleaseObject(object obj) { ... }

    // Execute the given method using an object from the pool
    public void ExecuteFromPool(Type t,
        UseObject executeDelegate, object [] args) { ... }
}

Figure 5 ReleaseObject Method
private void ReturnToPool(object obj, ObjectData data)
{
    Monitor.Enter(data);
    try
    {
        data.inUse—;

        int size = data.inUse + data.inPool;
        if (size < data.minPoolSize)
        {
            // Return actual object to the pool
            data.pool.Enqueue(obj);
            data.inPool++;
        }
        else
        {
            // Min available, so enqueue weak reference
            WeakReference weakRef = new WeakReference(obj);
            data.pool.Enqueue(weakRef);
        }

        // Notify waiting threads
        if (data.inWait > 0) Monitor.Pulse(data);
    }
    finally { Monitor.Exit(data); }
}

Figure 6 RetrieveFromPool Method
private object AllocateObject(ObjectData data)
{
    return data.createDelegate();
}

private object DequeueFromPool(ObjectData data)
{
    object result;
    do
    {
        // This presumes pool is non-empty
        result = data.pool.Dequeue();
        if (result is WeakReference)
            result = ((WeakReference)result).Target;
        else
            data.inPool—;

    } while (result == null && data.pool.Count > 0);

    return result;
}

private object RetrieveFromPool(ObjectData data)
{
    object result = null;
    int waitTime = (data.creationTimeout > 0) ?
        data.creationTimeout : Timeout.Infinite;

    try
    {
        // Try to obtain lock
        int startTick = Environment.TickCount;
        if (Monitor.TryEnter(data, waitTime) == false) return null;

        if (data.pool.Count > 0) result = DequeueFromPool(data);

        if (result == null)
        {
            // Pool empty or all weak refs
            if (data.maxPoolSize == 0 || data.inUse < data.maxPoolSize)
                result = AllocateObject(data);
            else
            {
                if (waitTime != Timeout.Infinite)
                    waitTime -= (Environment.TickCount - startTick);
                result = WaitForObject(data, waitTime);
            }
        }

       // Update inUse counter.
       if (result != null) data.inUse++;
  } 
  finally { Monitor.Exit(data); }

  return result;
}

Figure 7 ExecuteFromPool Method
private ObjectData GetObjectData(Type t)
{
    // The private ObjectData class holds stats for each type.
    ObjectData data = Table[t.FullName] as ObjectData;
    if (data == null) throw new ArgumentException(...);
    return data;
}

public void ExecuteFromPool(Type t, 
    UseObject executeDelegate, object [] args)
{
    ObjectData data = GetObjectData(t);

    object obj = null;
    try
    {
        // Retrieve an object from the pool
        obj = RetrieveFromPool(data);
        if (obj == null) throw new ObjectPoolException(...);

        // Execute given delegate with pooled object
        executeDelegate(obj, args);
    }
    finally
    {
        // Return retrieved object to pool
        if (obj != null) ReturnToPool(obj, data);
    }
}

Figure 8 File Streaming
static void ProcessFile(FileStream fin, FileStream fout)
{
    int next;
    while ((next = fin.ReadByte()) != -1)
    {
        byte b = (byte)next;
        if (b == 'n' || b == 'N')
          CheckForWordAndWrite(fin, fout, "nation", "country", b);
        else if (b == 'l' || b == 'L')
          CheckForWordAndWrite(fin, fout, "liberty", "freedom", b);
        else
          fout.WriteByte(b);
    }
}

static void CheckForWordAndWrite(Stream si, Stream so,
    string word, string replace, byte first)
{
    int len = word.Length;

    long pos = si.Position;
    byte[] buf = new byte[len];
    buf[0] = first;
    si.Read(buf, 1, word.Length-1);

    string data = Encoding.ASCII.GetString(buf);
    if (String.Compare(word, data, true) == 0)
        so.Write(Encoding.ASCII.GetBytes(replace), 0, replace.Length);
    else
    {
        si.Position = pos;    // reset stream
        so.WriteByte(first);  // write orig byte
    }
}
 

版权所有:UML软件工程组织