Поделюсь опытом как уменьшить вероятность ошибок. Этот текст я держу в папке с каждым крупным проектом, для себя и потомков. Вообще таких рекомендаций гораздо больше, например
Object Pascal Style Guide - это как правила дорожного движения, кто их соблюдает, меньше попадает в аварии.
Все предупреждения компилятора и проверки в рантайме должны быть включены.
Все имена должны иметь однозначный смысл. Короткие имена допустимы только в коротких блоках.
ВНИМАНИЕ! При инициализации и финализации DLL нельзя создавать или удалять фоновые процессы TThread а также любые объекты, использующие TThread! Также внутри DLL нежелательно использовать Sleep(0), но можно Sleep(1) или больше.
DLL использовать как библиотеку функций, избегать вызова кода основной программы из DLL и обработки данных внутри обратных вызовов.
При работе с динамически создаваемыми объектами следует придерживаться правила, что создание и удаление должно происходить в одном модуле, как можно ближе друг к другу. В идеале так:
- Код: Выделить всё
Obj := TObj.Create();
try
Obj.Use();
finally
Obj.Free();
end;
Все объекты, доступные за пределами функции/процедуры/метода должны удаляться при помощи FreeAndNil().
Необходимо следить за утечками памяти, объектов USER и GDI. Проверить можно многократным созданием-удалением форм и объектов.
В конструкторе лучше не трогать наследуемые свойства, они могут вызвать цепную реакцию. Только из секции private.
Всегда использовать модификатор const для параметров типа string, record, array, если это не возвращаемый параметр. В этом случае параметр передается по ссылке (не создается временный дубликат) и защищен от записи. Пример: procedure(const AStr: string);
По возможности, вместо CriticalSection использовать атомарные операции InterlockedIncrement / InterlockedExchangeAdd. Для атомарного изменения буфера или объекта заранее подготовить копию с новыми данными и подменить указатель на буфер или объект при помощи InterlockedExchange.
Для каждого фонового потока создавать свой экземпляр (копию) данных. Внутри фонового потока глобальные переменные и объекты использовать только для чтения, а лучше совсем не использовать.
procedure(var Str: string) лучше, чем function(): string, поскольку не вызывает блокировки и сброса кеша CPU.
Для парсинга статичный буфер лучше, чем строка или динамический массив. Парсить строки лучше при помощи PosEx() вместо перебора по индексу.
TMemoryStream желательно лишний раз не создавать-удалять и не изменять размер. В пределах размера можно творить что угодно.
И вообще объекты и буферы лучше лишний раз не создавать-удалять, а использовать повторно.
Тестирование модулей и процедур с запредельными нагрузками, в несколько потоков, с замером производительности и потребления ресурсов - может показать проблемы, незаметные в обычных условиях.