Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
CSharpNotesForProfessionals.pdf
Скачиваний:
66
Добавлен:
20.05.2023
Размер:
6.12 Mб
Скачать

Chapter 162: Garbage Collector in .Net

Section 162.1: Weak References

In .NET, the GC allocates objects when there are no references left to them. Therefore, while an object can still be reached from code (there is a strong reference to it), the GC will not allocate this object. This can become a problem if there are a lot of large objects.

A weak reference is a reference, that allows the GC to collect the object while still allowing to access the object. A weak reference is valid only during the indeterminate amount of time until the object is collected when no strong references exist. When you use a weak reference, the application can still obtain a strong reference to the object, which prevents it from being collected. So weak references can be useful for holding on to large objects that are expensive to initialize, but should be available for garbage collection if they are not actively in use.

Simple usage:

WeakReference reference = new WeakReference(new object(), false);

GC.Collect();

object target = reference.Target; if (target != null)

DoSomething(target);

So weak references could be used to maintain, for example, a cache of objects. However, it is important to remember that there is always the risk that the garbage collector will get to the object before a strong reference is reestablished.

Weak references are also handy for avoiding memory leaks. A typical use case is with events.

Suppose we have some handler to an event on a source:

Source.Event += new EventHandler(Handler)

This code registers an event handler and creates a strong reference from the event source to the listening object. If the source object has a longer lifetime than the listener, and the listener doesn't need the event anymore when there are no other references to it, using normal .NET events causes a memory leak: the source object holds listener objects in memory that should be garbage collected.

In this case, it may be a good idea is to use the Weak Event Pattern.

Something like:

public static class WeakEventManager

{

public static void SetHandler<S, TArgs>( Action<EventHandler<TArgs>> add, Action<EventHandler<TArgs>> remove,

S subscriber,

Action<S, TArgs> action) where TArgs : EventArgs where S : class

{

var subscrWeakRef = new WeakReference(subscriber); EventHandler<TArgs> handler = null;

GoalKicker.com – C# Notes for Professionals

765

handler = (s, e) =>

{

var subscrStrongRef = subscrWeakRef.Target as S; if (subscrStrongRef != null)

{

action(subscrStrongRef, e);

}

else

{

remove(handler); handler = null;

}

};

add(handler);

}

}

and used like this:

EventSource s = new EventSource(); Subscriber subscriber = new Subscriber();

WeakEventManager.SetHandler<Subscriber, SomeEventArgs>(a => s.Event += a, r => s.Event -= r, subscriber, (s,e) => { s.HandleEvent(e); });

In this case of course we have some restrictions - the event must be a

public event EventHandler<SomeEventArgs> Event;

As MSDN suggests:

Use long weak references only when necessary as the state of the object is unpredictable after finalization.

Avoid using weak references to small objects because the pointer itself may be as large or larger.

Avoid using weak references as an automatic solution to memory management problems. Instead, develop an e ective caching policy for handling your application's objects.

Section 162.2: Large Object Heap compaction

By default the Large Object Heap is not compacted unlike the classic Object Heap which can lead to memory fragmentation and further, can lead to OutOfMemoryExceptions

Starting with .NET 4.5.1 there is an option to explicitly compact the Large Object Heap (along with a garbage collection):

GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;

GC.Collect();

Just as any explicit garbage collection request (it's called request because the CLR is not forced to conduct it) use with care and by default avoid it if you can since it can de-calibrate GCs statistics, decreasing its performance.

GoalKicker.com – C# Notes for Professionals

766

Chapter 163:

Microsoft.Exchange.WebServices

Section 163.1: Retrieve Specified User's Out of O ce Settings

First let's create an ExchangeManager object, where the constructor will connect to the services for us. It also has a GetOofSettings method, which will return the OofSettings object for the specified email address :

using System;

using System.Web.Configuration;

using Microsoft.Exchange.WebServices.Data;

namespace SetOutOfOffice

{

class ExchangeManager

{

private ExchangeService Service;

public ExchangeManager()

{

var password = WebConfigurationManager.ConnectionStrings["Password"].ConnectionString; Connect("exchangeadmin", password);

}

private void Connect(string username, string password)

{

var service = new ExchangeService(ExchangeVersion.Exchange2010_SP2); service.Credentials = new WebCredentials(username, password); service.AutodiscoverUrl("autodiscoveremail@domain.com" ,

RedirectionUrlValidationCallback);

Service = service;

}

private static bool RedirectionUrlValidationCallback(string redirectionUrl)

{

return redirectionUrl.Equals("https://mail.domain.com/autodiscover/autodiscover.xml");

}

public OofSettings GetOofSettings(string email)

{

return Service.GetUserOofSettings(email);

}

}

}

We can now call this elsewhere like this:

var em = new ExchangeManager();

var oofSettings = em.GetOofSettings("testemail@domain.com");

Section 163.2: Update Specific User's Out of O ce Settings

Using the class below, we can connect to Exchange and then set a specific user's out of o ce settings with

UpdateUserOof:

using System;

using System.Web.Configuration;

using Microsoft.Exchange.WebServices.Data;

GoalKicker.com – C# Notes for Professionals

767

class ExchangeManager

{

private ExchangeService Service;

public ExchangeManager()

{

var password = WebConfigurationManager.ConnectionStrings["Password"].ConnectionString; Connect("exchangeadmin", password);

}

private void Connect(string username, string password)

{

var service = new ExchangeService(ExchangeVersion.Exchange2010_SP2); service.Credentials = new WebCredentials(username, password);

service.AutodiscoverUrl("autodiscoveremail@domain.com" , RedirectionUrlValidationCallback);

Service = service;

}

private static bool RedirectionUrlValidationCallback(string redirectionUrl)

{

return redirectionUrl.Equals("https://mail.domain.com/autodiscover/autodiscover.xml");

}

///<summary>

///Updates the given user's Oof settings with the given details

///</summary>

public void UpdateUserOof(int oofstate, DateTime starttime, DateTime endtime, int externalaudience, string internalmsg, string externalmsg, string emailaddress)

{

var newSettings = new OofSettings

{

State = (OofState)oofstate,

Duration = new TimeWindow(starttime, endtime), ExternalAudience = (OofExternalAudience)externalaudience, InternalReply = internalmsg,

ExternalReply = externalmsg

};

Service.SetUserOofSettings(emailaddress, newSettings);

}

}

Update the user settings with the following:

var oofState = 1;

var startDate = new DateTime(01,08,2016); var endDate = new DateTime(15,08,2016); var externalAudience = 1;

var internalMessage = "I am not in the office!";

var externalMessage = "I am not in the office <strong>and neither are you!</strong>" var theUser = "theuser@domain.com";

var em = new ExchangeManager();

em.UpdateUserOof(oofstate, startDate, endDate, externalAudience, internalMessage, externalMessage, theUser);

Note that you can format the messages using standard html tags.

GoalKicker.com – C# Notes for Professionals

768