Все просто: иди с
sb = null;
и забудь обо всем остальном.
Почему? Как только GC может решить, что объект имеет право на сборку мусора, он также знает, что все вещи, на которые ссылается этот объект, являются приемлемыми. И учитывая тот факт, что у вас нет никакого контроля над тем, как ГХ запускает, очищает объекты и освобождает память, приведенное выше назначение действительно достаточно хорошо.
Когда он четко сообщает ваше намерение, а затем помогает ГК выполнять свою работу. На самом деле хорошо написанный код, вероятно, даже не нуждается в этом утверждении.
Теперь, может быть, это на самом деле не достаточно хорошо. Но тогда мы будем говорить о реальной проблеме производительности, в очень четком и узком контексте. В этом случае вы не полагаетесь на слухи, вы начинаете измерять.
Другими словами: если у вас нет реальной проблемы с производительностью, которая проявляется в вашей настройке и требует действий, тогда вы идете с простым и понятным кодом, избегая всех видов оптимизаций на уровне исходного кода. Но если у вас есть реальная проблема с производительностью, то вы соответствующим образом относитесь к ней: определяя основную причину и, вероятно, измеряя , как различные варианты работают в реальности.
Все остальное пахнет преждевременной оптимизацией!
Я исправил ошибку однажды где приложение, разрушаемое каждый день в 18:12.
Выпущенный, что кто-то сохранил число секунд начиная с запуска дня в интервале на 16 битов.
Я не могу сказать Вам определенную ошибку, с которой я столкнулся, но я могу сказать, что Вы включили по крайней мере одно из следующего:
На самом деле это - список причин всех моих ошибок ;)
Да ведь я никогда не производил ошибку в своей жизни!
Как это для ошибки, это будет управлять Вами сумасшедшая попытка выяснить то, что продолжается:
#if CONFIG_SETTING == 1
#define SOME_MACRO( x) doSomething( x);
#else
#define SOME_MAcRO( x) // don't do it in retail
#endif
void foo( int a, int b)
{
if (a < b) SOME_MACRO( a);
alwaysCallThisFcn();
// ...
}
Таким образом, если CONFIG_SETTING равняется 1, нечто () компилируется как:
void foo( int a, int b)
{
if (a < b) doSomething( a);; // note: the second
// semi-colon has no effect
alwaysCallThisFcn();
// ...
}
Иначе это компилируется как:
void foo( int a, int b)
{
if (a < b)
alwaysCallThisFcn(); // now alwaysCallThisFcn() is
// called conditionally
// ...
}
В былые времена, когда у нас был код карт, я работал в течение трех дней, пытаясь выяснить, почему мои пакетные задания не работали. Я наконец был до операторов печати о каждых трех строках, и я не видел НИ ОДНОГО из них.
Затем я понял, что была ошибка JCL, которая мешала моей программе загружаться в соответствующий набор данных (думайте, "не входил в путь"), таким образом, я выполнял то же старое изображение, много раз, вместо недавно скомпилированного.
Не мое худшее, но недавний пример зла тернарного оператора:
Меня озадачил некоторое время, почему columnCSV был всегда пуст:
foreach(Column column in Table.Columns)
{
columnsCSV += string.IsNullOrEmpty(columnsCSV) ? "" : "," + column.Name;
}
Должен был быть
foreach(Column column in Table.Columns)
{
columnsCSV += (string.IsNullOrEmpty(columnsCSV) ? "" : ",") + column.Name;
}
P.S. Проигнорируйте 'отсутствие StringBuilder' зло.
Я однажды отлаживал программу, которая была многопоточной, но где многопоточность могла быть отключена. Программа была бы segfault случайным образом, но только с включенной многопоточностью. После попытки изолировать каждое возможное состояние состязания, я понял, что единственная проблема состояла в том, что я писал мимо связанного массива. В однопоточном режиме средство выделения памяти выделяло память очевидно, такой, что данные в адресе непосредственно выше этого массива больше были не нужны к тому времени, когда это было перезаписано, таким образом, ошибка не имела никаких признаков. В многопоточном режиме данные в этих адресах были данными, принадлежавшими другим потокам.
Кроме того, как может мы забывать ошибки, представленные злом КОПИИ И ВСТАВКИ!!
Однажды, когда я делал некоторую математику, программируя связанную домашнюю работу, мне потребовались несколько часов, чтобы выяснить, что я имел + где-нибудь, где мне было нужно *.
Это не моя ошибка, но я присутствовал для нее. Моя Жена и я посещали урок Java вместе, когда мы были в колледже. Она находится в Антропологии, и я нахожусь в финансах, но так или иначе мы закончили в Java.Мне очень понравилось.
Она провела весь вечер, пытаясь заставить "проклятую программу потянуть глупый % $ ^&* (дом на экране", и просто не мог. Будучи упрямой, она сопротивлялась какой-либо моей помощи до ее заключительного момента отчаяния (2:00, 3:00?). Я бросил беглый взгляд и уведомление, она использовала "O" (буква O) вместо "0" (нуль) повсюду.
Она ушла из класса на следующий день.
Лично, у меня есть несколько немых ошибок, которые могут быть частыми. Мое избранное:
знак доллара + function_name использование того же уже выполняет итерации ($i) вместо этого, $i цикличного выполнения выполняют итерации цикла случайное", '" который произошел ГДЕ-НИБУДЬ потому что моя подсунутая рука
Когда я был намного менее опытным с изогнутым языком фигурной скобки, я однажды записал что-то вроде:
if (expr);
stmt;
Это было во встроенной системе, таким образом, мой отладчик и printf были бессильны. Это просто сделало аудио звук плохо. Я подавил его к низкой производительности и провел приблизительно один день оптимизация его. Задняя часть вычисления конверта показала бы, что производительность не была проблемой.
С того дня я всегда вставлял свои фигурные скобки. Это заставляет меня хотеть записать в Python, если это не было для остальной части языка.
Давно в мои дни средней школы CS, я реализовал двоичное дерево в (я думаю), Turbo Pascal. Одна из операций не вполне обработала свои указатели правильно и закончила тем, что перезаписала части сегмента кода (ах, радости программирования DOS). Так или иначе это всегда заканчивало тем, что перезаписало весь код отладки, который я вставил, делающие операторы IF по-видимому лежат, операторы печати не происходят, и т.п., но все удивительно без катастрофического отказа, и сделали в значительной степени невозможным сказать то, что продолжалось.
В конечном счете я выполнил его через отладчик уровня ассемблера и поймал проблему, когда инструкции начали изменяться посреди функции...
Не уверенный, если это было самым глупым, но самое противное, я когда-либо имел, был то, где я записал некоторые стандартные программы управления доступом, которые зависели частично от времени суток (таким образом, Вы могли записать, что к правилам как 'это можно только получить доступ в рабочий день в течение рабочего дня').
Я закончил код и запустил все мои тесты, и все хорошо работало. Затем я пошел домой, приехал в следующий рабочий день и запустил все свои тесты, и они перестали работать. Я не мог ни за что в жизни выяснить, почему это произошло, так как код и все тесты были абсолютно неизменны.
Выпущенный то, что летнее время умерло, и мой код, не обработало это.
Не на самом деле инициализируя некоторую переменную стека около запуска основного. Вещь обнулить автоматически, хорошо почти всегда.
Большинство моих глупых ошибок не было фактическими ошибками. Они были неправильными данными и моими предположениями о тех данных.
Я провел часы, пытаясь найти ошибку в коде, где не было одного - я отлаживал старую часть кода, или я предположил, что мой набор данных тестирования был чем-то..., и это не было.
for i = 0 to ( list.Length - 1 ) do
begin
DoSomething( 1 );
end;
Попытайтесь найти это на вшивом мониторе с крошечным шрифтом в 3:00!;)
После того как я записал функцию для парсинга строки даты и времени в другой формат. В нем у меня был переключатель/оператор выбора, который анализирует значения месяца, это было похоже на это:
case month of:
01: return "Jan"; break;
02: return "Feb"; break;
... etc ...
09: return "Sep"; break;
11: return "Nov"; break;
12: return "Dec"; break;
end;
По некоторым причинам я не учел октябрь...
I=1
Та одна строка Фортрана просто не работала.
После нескольких часов бесплодной отладки я глотал свою гордость и сделал, чтобы приятель ступил через код со мной.
После прибытия в ту строку я сказал, "и теперь мы увеличиваем нижний индекс".
"Ха?" говорит он.
Именно тогда я понял, что читал свое намерение:
I=I+1
вместо того, что я записал.
Помните, что в следующий раз Вы застреваете и не можете выяснить что случилось.
Не позволяйте своей гордости помешать Вам принимать на работу вторую пару глаз.
В C/C++ (который я недавно изучил),
if (x = 0) {
...
}
Я писал синтаксический анализатор с помощью гибкого провода/бизона. Функцией была оптимизация сворачивания констант, т.е. замена 20 + 2 с 22, однако мой синтаксический анализатор заменял ее 4.
Как часть лексического анализатора у меня была таблица символов. Я использовал линейный поиск с strncpy для поиска существующих записей. Однако для параметра длины в strncpy я использовал strlen на строке в таблице символов. Не умная мысль, потому что, если запись в таблице символов меньше затем та, добавляемая, она будет неправильно соответствовать. Например, добавление "20" соответствовало бы к "2", потому что только первый символ сравнен. Поэтому, когда мой синтаксический анализатор искал символ для "20", это добралось "2". Я взял меня часы для выяснения, почему мои 20-е изменялись на 2 с.