Программирование мобильных устройств на платформе .NET Compact Framework - Иво Салмре
Шрифт:
Интервал:
Закладка:
//Вызывается для освобождения от любых графических
//ресурсов, которые могли быть кэшированы
//------------------------------------------------
private static void g_CleanUpDrawingResources() {
//Освободить память от черного пера, если таковое имеется
if (s_blackPen !=null) {
s_blackPen.Dispose();
s_blackPen = null;
}
// Освободить память от белого пера, если таковое имеется
if (s_whitePen != null) {
s_whitePen.Dispose();
r_whitePen = null;
}
//Освободить память от атрибута ImageAttribute, если таковой имеется.
//Примечание. Метод Dispose() для этого типа не предусмотрен,
//поскольку все его данные являются управляемыми
if (s_ImageAttribute != null) {
s_ImageAttribute = null;
}
//Освободить память от полужирного шрифта, если таковой имеется
if (s_boldFont != null) {
s_boldFont.Dispose();
s_boldFont = null;
}
}
//-----------------------------------------
//Эта функция позволяет получить доступ
//к черному перу, находящемуся в кэш-памяти
//-----------------------------------------
private static System.Drawing.Pen g_GetBlackPen() {
//Если перо еще не существует, создать его
if (s_blackPen ==null) {
s_blackPen = new System.Drawing.Pen(System.Drawing.Color.Black);
}
//Возвратить черное перо return s_blackPen;
}
//----------------------------------------
//Эта функция позволяет получить доступ
//к белому перу, находящемуся в кэш-памяти
//----------------------------------------
private static System.Drawing.Pen g_GetWhitePen() {
//Если перо еще не существует, создать его
if (s_whitePen == null) {
s_whitePen = new System.Drawing.Pen(System.Drawing.Color.White);
}
//Возвратить белое перо return s_whitePen;
}
//-----------------------------------------------
//Эта функция позволяет получить доступ
//к полужирному шрифту, находящемуся в кэш-памяти
//-----------------------------------------------
private static System.Drawing.Font g_GetBoldFont() {
//Если перо еще не существует, создать его
if (s_boldFont ==null) {
s_boldFont = new System.Drawing.Font(
System.Drawing.FontFamily.GenericSerif, 10, System.Drawing.FontStyle.Bold);
}
//Возвратить полужирный шрифт
return s_boldFont;
}
//------------------------------------------------------
//Эта функция позволяет осуществлять доступ
//к находящемуся в кэш-памяти объекту imageAttributes,
// который мы используем для изображений с прозрачностью
//------------------------------------------------------
private static System.Drawing.Imaging.ImageAttributes g_GetTransparencyImageAttribute() {
//Если объект не существует, создать его
if (s_ImageAttribute == null) {
//Создать атрибут изображения
s_ImageAttribute = new System.Drawing.Imaging.ImageAttributes();
s_ImageAttribute.SetColorKey(System.Drawing.Color.White, System.Drawing.Color.White);
}
//Возвратить его
return s_ImageAttribute;
}
} //Конец класса
Управление памятью на микроскопическом "уровне алгоритма"
Современные языки программирования, библиотеки классов и управляемые среды времени выполнения позволили значительно повысить продуктивность написания программ. В то же время, избавляя программиста от необходимости задумываться о низкоуровневом распределении памяти, в котором нуждаются алгоритмы, они невольно создают предпосылки для написания неэффективного кода. Неэффективность кода может быть обусловлена причинами двоякого рода:
1. Вычислительная неэффективность алгоритма. Этот вид неэффективности наблюдается в тех случаях, когда спроектированный вами алгоритм предусматривает интенсивные вычисления или выполнение большего количества циклов, чем это объективно необходимо, от чего можно было бы избавиться, используя более эффективные алгоритмы. В качестве классического примера можно привести сортировку массива данных. Иногда у вас может появляться возможность выбирать между несколькими возможными вариантами алгоритмов сортировки, отдельными частными случаями которых могут, например, быть алгоритмы "порядка N" (линейная зависимость времени вычислений от количества сортируемых элементов), "порядка N*Log(N)" (зависимость времени вычислений от количества сортируемых элементов отличается от линейной, но остается все же лучшей, чем экспоненциальная) или "порядка N^2" (экспоненциальная зависимость времени вычислений от количества сортируемых элементов). Кроме вышеперечисленных "порядков" возможно множество других (например, N^3). Выбор наиболее подходящего алгоритма зависит от объема данных, с которыми вы работаете, объема доступной памяти и ряда других факторов, например, от состояния рабочих данных. Отдельные стратегии, например, предварительная обработка данных перед отправкой их на устройство или хранение данных в формате, специфическом для использования памяти в качестве хранилища, способны обеспечить значительное повышение производительности алгоритма. Существует огромное количество компьютерной литературы, посвященной проектированию эффективных алгоритмов и оценке их быстродействия, поэтому никаких попыток более подробного анализа этих вопросов в данной книге не делается. Необходимо только отметить, что чем больше объем обрабатываемых данных, тем ответственнее необходимо отнестись к принятию решения относительно выбора вычислительного алгоритма. Во всех затруднительных случаях тщательно анализируйте алгоритм и обращайтесь к существующей литературе по этому вопросу. Очень часто оказывается так, что кто-то другой уже прошел этот путь, и вам остается лишь перенять их опыт.
2. Неэффективное распределение памяти. После того как вы определитесь со стратегией алгоритма, следующим фактором, от которого в значительной степени за висит производительность приложения, является способ реализации этого алгоритма. При этом едва ли не наибольшие усилия вы должны приложить к тому, чтобы избежать распределения лишних объемов памяти, особенно если память распределяется в циклах. В данном разделе этой книги основное внимание уделяется именно этому вопросу.
Вашей целью должно быть распределение "нулевых объемов памяти" внутри циклов в написанном вами коде. Существуют случаи, когда это является неизбежным, как, например, при построении дерева объектов, которое требует размещения в памяти новых узлов для помещения их в иерархическую структуру. Во многих других случаях эффективность приложения можно существенно повысить, тщательно анализируя распределение памяти для каждого объекта и рассматривая альтернативные решения. Чего, как правило, следует избегать — так это выполнения операций размещения объектов в памяти и удаления их из памяти внутри алгоритмических циклов.
Пишите аккуратные алгоритмы: не сорите!
Как и в реальной жизни, сор в программировании — это отходы производственной деятельности, которые должны выбрасываться. Обычно сор появляется в результате неряшливости и неаккуратности. Стремление к получению кратковременных удобств часто порождает долговременные проблемы. При создании в алгоритмах мусора в виде временных объектов, необходимости в которых на самом деле нет, работа приложения замедляется в результате воздействия непосредственных и косвенных факторов:
1. Непосредственные факторы. Каждый раз, когда вы создаете объект, перед его использованием должна быть распределена и инициализирована память. Это прямые предварительные расходы, которые должен оплатить ваш алгоритм.
2. Косвенные факторы. После того как приложение освободило объект, он становится "мусором" Этот мусор накапливается в приложении, пока его не соберется так много, что для последующего распределения памяти для новых объектов потребуется ее предварительная очистка от старых. Конечно же, именно это и называется сборкой мусора. На сборку мусора уходит определенное время, и если мусора много, то эта операция заметно затормозит работу вашего приложения. Чем больше вы сорите, тем больше накапливается мусора и тем чаще приходится тратить время на уборку!
В процессе программирования вы всегда должны стараться "сорить" как можно меньше. Нет ничего плохого в том, чтобы создать экземпляр объекта, если это помогает решить какую-то очень важную задачу; если же объект является короткоживущим и задача может быть решена без него, то вы только создаете мусор. Не будьте "неряхой"!