2008-11-07 3 views
27

Должны ли объекты Singleton, которые не используют экземпляры экземпляра/ссылки, считаться утечками памяти в C++?Singleton Destructors

Без счетчика, который требует явного удаления экземпляра singleton, когда счетчик равен нулю, как объект удаляется? Убирается ли она ОС при завершении приложения? Что, если этот Синглтон выделил память в кучу?

Вкратце, мне нужно вызвать деструктор Singelton или я могу полагаться на его очистку, когда приложение завершается?

ответ

14

Вы можете положиться на то, что он очищается операционной системой.

Сказанное: если вы находитесь на мусорном собрании с финализаторами, а не с деструкторами, вы можете захотеть иметь изящную процедуру выключения, которая может полностью закрыть ваши синглтоны напрямую, чтобы они могли освободить любые критические ресурсы в случае использования системных ресурсов которые не будут правильно очищены, просто закончив приложение. Это потому, что в большинстве языков финализаторы работают на основе «лучших усилий». С другой стороны, очень мало ресурсов, которые нуждаются в такой надежности. файловые дескрипторы, память и т. д. все возвращаются к ОС чисто независимо.

Если вы используете одиночный лингтон, который лениво выделяется (то есть с идиомой блокировки с тройной проверкой) на языке, таком как C++ с реальными деструкторами, а не с финализаторами, тогда вы не можете полагаться на его деструктор, вызываемый во время выключения программы. Если вы используете один статический экземпляр, деструктор будет запускаться после завершения основных завершений в какой-то момент.

Независимо от того, когда процесс завершается, вся память возвращается в операционную систему.

0

Любая память кучи, выделенная вашим процессом и не освобожденная (удаленная), будет восстановлена ​​ОС. Если вы используете наиболее распространенную реализацию singleton, которая использует статические переменные, это также будет очищено от завершения вашего приложения.

* Это не означает, что вы должны ходить по новым указателям и никогда не чистить их.

1

A singleton будет одним экземпляром вашего объекта. Вот почему он не требует счетчика. Если он будет существовать для длины вашего приложения, то деструктор по умолчанию будет в порядке. В любом случае память будет восстановлена ​​операционной системой, когда процесс завершится.

3

Любые виды распределения, за исключением разделяемых памяти, автоматически очищаются операционной системой, когда процесс завершается. Поэтому вам не нужно явно обращаться к деструктору singleton. Другими слова нет утечки ...

Кроме того типичный одноточечно реализации как в Мейерсе Singleton не только поточно во время инициализации по первому зову, но и гарантированно Изящным прекратить при выходе из приложения (деструктор вызывается).

Во всяком случае, если заявка отправляется сигнал UNIX (например: SIGTERM или SIGHUP) поведение по умолчанию для завершения процесса без вызова деструкторов статических выделенных объектов (Singletons). Чтобы преодолеть эту проблему для этих сигналов, можно вывести обработчик, вызывающий выход, или вывести выход таким обработчиком - signal(SIGTERM,exit);

+0

Если вы полагаетесь на библиотеку времени выполнения, которая уничтожает ваши статические объекты после основных возвратов, и вы надеетесь, что это будет возможно использовать код в (Windows) DLL, тогда вы запускаете код во время DllMain, и большинство вещей, которые вы можете использовать делать это небезопасно. – 2010-08-13 20:32:00

1

Зависит от вашего определения утечки.Unbound memory увеличивается утечка в моей книге, singleton не несвязан. Если вы не указали подсчет ссылок, вы намеренно сохраните экземпляр в активном состоянии. Не случайно, а не утечка.

Ваш деструктор оболочки singleton должен удалить экземпляр, он не является автоматическим. Если он просто выделяет память и нет ресурсов ОС, нет смысла.

11

Вы должны явно очистить все объекты. Никогда не полагайтесь на ОС, чтобы очистить вас.

Где я обычно использую singleton - это инкапсулировать управление чем-то вроде файла, аппаратного ресурса и т. Д. Если я не правильно очищаю это соединение, я могу легко протечь системные ресурсы. При следующем запуске приложения он может выйти из строя, если ресурс по-прежнему заблокирован предыдущей операцией. Другая проблема может заключаться в том, что любая финализация, такая как запись буфера на диск, может не произойти, если она все еще существует в буфере, принадлежащем экземпляру singleton.

Это не проблема утечки памяти - проблема в том, что вы можете утечка ресурсов, отличных от памяти, которые могут быть не так легко восстановлены.

+0

+1 действительно, но некоторые синглеты обеспечивают вызов деструктора, когда приложение выходит. – 2008-11-08 11:33:23

+1

Если вы полагаетесь на библиотеку времени выполнения, которая уничтожает ваши статические объекты после основных возвратов, и вы надеетесь, что это будет возможно использовать код в (Windows) DLL, тогда вы запускаете код во время DllMain, и большинство вещей, которые вам могут понравиться они небезопасны. – 2010-08-13 20:31:25

9

Каждый язык и окружающая среда будут отличаться, хотя я согласен с @Aaron Fisher в том, что одноэлемент имеет тенденцию существовать на протяжении всего процесса.

В примере C++, с использованием обычной одноплодной идиомы:

Singleton &get_singleton() 
{ 
    static Singleton singleton; 
    return singleton; 
} 

экземпляр Singleton будет построен первый раз, когда вызывается функция, и тот же экземпляр будет иметь это деструктор вызывается во время глобальных статического фаза деструктора при выключениях программы.

20

Как часто, «это зависит». В любой операционной системе, достойной имени, когда ваш процесс завершается, все память и другие ресурсы, используемые локально внутри процесса, будут выпущены. Вам просто не нужно об этом беспокоиться.

Однако, если ваш синглтон выделяет ресурсы со временем жизни вне собственного процесса (возможно, файл, именованный мьютекс или что-то подобное), тогда вам нужно рассмотреть соответствующую очистку.

RAII поможет вам здесь. Если у вас есть сценарий, как это:

class Tempfile 
{ 
Tempfile() {}; // creates a temporary file 
virtual ~Tempfile(); // close AND DELETE the temporary file 
}; 

Tempfile &singleton() 
{ 
    static Tempfile t; 
    return t; 
} 

... то вы можете быть уверены, что ваш временный файл будет закрыт и удален, однако ваши выходы приложений. However, this is NOT thread-safe, and the order of object deletion may not be what you expect or require.

однако, если синглтон реализуется как НАСТОЯЩЕГО

Tempfile &singleton() 
{ 
    static Tempfile *t = NULL; 
    if (t == NULL) 
    t = new Tempfile(); 
    return *t; 
} 

... то у вас есть другая ситуация. Память, используемая вашим tempfile, будет восстановлена, но файл НЕ будет удален, потому что деструктор не будет вызван.

3

Как вы создаете объект?

Если вы используете глобальную переменную или статическую переменную, деструктор будет вызываться, предполагая, что программа завершается нормально.

Например, программа

#include <iostream> 

class Test 
{ 
    const char *msg; 

public: 

    Test(const char *msg) 
    : msg(msg) 
    {} 

    ~Test() 
    { 
     std::cout << "In destructor: " << msg << std::endl; 
    } 
}; 

Test globalTest("GlobalTest"); 

int main(int, char *argv[]) 
{ 
    static Test staticTest("StaticTest"); 

    return 0; 
} 

печать из

In destructor: StaticTest 
In destructor: GlobalTest 
2

Это фольклор освободить глобальные распределения памяти в явном виде, прежде чем завершает приложение. Полагаю, большинство из нас это делает по привычке и потому, что мы чувствуем, что плохо «забывать» о структуре. В мире C это закон симметрии, что какое-либо распределение должно иметь место для освобождения. Программисты на С ++ думают иначе, если они знают и практикуют RAII.

В старые добрые времена, например, У AmigaOS были утечки REAL. Когда вы забыли освободить память, он НИКОГДА не станет доступен снова, пока система не будет сброшена.

В наши дни я не знаю какой-либо уважающей себя настольной операционной системы, которая бы позволяла утечкам памяти выходить из виртуального адресного пространства приложения. Ваш пробег может зависеть от встроенных устройств, когда нет обширной памяти.

0

В таких языках, как C++, которые не имеют сбор мусора, лучше всего очистить до прекращения. Вы можете сделать это с помощью класса друзей деструктора.

class Singleton{ 
... 
    friend class Singleton_Cleanup; 
}; 
class Singleton_Cleanup{ 
public: 
    ~Singleton_Cleanup(){ 
     delete Singleton::ptr; 
    } 
}; 

Создать очистку класса при запуске программы, а затем при выходе из деструктора будет называться очисткой синглтона. Это может быть более подробным, чем позволить ему перейти в операционную систему, но оно следует принципам RAII и в зависимости от ресурсов, выделенных в вашем одноэлементном объекте, это может быть необходимо.