Для тех, кто находит это в будущем, я бы не рекомендовал использовать mail
. Есть несколько ответов, которые касаются этого, но не из-за этого.
Функция PHP mail
не только непрозрачна, но и полностью зависит от того, какой MTA вы используете (то есть Sendmail) для выполнения этой работы. mail
будет ТОЛЬКО сообщать вам, не удалось ли MTA принять его (т. е. Sendmail был отключен, когда вы пытались отправить). Он не может сказать вам, была ли почта успешной, потому что она была передана. Как таковой (как детали ответов Джона Конде), вы теперь можете возиться с журналами MTA и надеяться, что он расскажет вам об отсутствии возможности исправить его. Если вы находитесь на общем хосте или не имеете доступа к журналам MTA, вам не повезло. К сожалению, по умолчанию для большинства ванильных инсталляций для Linux обрабатывается так.
Почтовая библиотека ( PHPMailer , Zend Framework 2+ и т. д.) делает что-то очень отличное от mail
. То, что они делают, это открыть сокет непосредственно на принимающем почтовом сервере, а затем отправить SMTP-почтовые команды непосредственно через этот сокет. Другими словами, класс действует как собственный MTA (обратите внимание, что вы можете сказать библиотекам использовать mail
, чтобы в конечном итоге отправить почту, но я настоятельно рекомендую вам не делать этого).
Что это означает, что вы можете непосредственно видеть ответы с принимающего сервера (например, в PHPMailer вы можете включить вывод отладки ). Больше не гадать, если почта не была отправлена или почему.
Если вы используете SMTP (то есть вы вызываете
isSMTP()
), вы можете получить подробную расшифровку протокола SMTP, используя свойствоSMTPDebug
.Установите этот параметр, включив в свой скрипт такую строку:
$mail->SMTPDebug = 2;
Вы также получаете преимущество лучшего интерфейса. С помощью
Почти каждая современная операционная система восстанавливает все выделенное пространство памяти после выхода программы. Единственное исключение, о котором я могу думать, может быть чем-то вроде Palm OS, где статическое хранилище и операционная память программы - почти то же самое, поэтому не освобождение может привести к тому, что программа займет больше места. (Я только размышляю здесь.)
. Как правило, в этом нет вреда, кроме того, что затраты времени на установку имеют больше памяти, чем вам нужно. Конечно, в примере, который вы даете, вы хотите сохранить память для переменной, которая может использоваться до тех пор, пока она не будет очищена.
Однако считается, что это хороший стиль для освобождения памяти, как только вам это не понадобится и освободить все, что у вас есть на выходе программы. Это больше упражнение в понимании того, какую память вы используете, и думать о том, все еще вам нужно. Если вы не отслеживаете, у вас могут быть утечки памяти.
С другой стороны, подобное напоминание о закрытии ваших файлов при выходе имеет гораздо более конкретный результат - если вы этого не сделаете, данные вы написали им, что их не покраснели, или если они временный файл, они могут не удаляться, когда вы закончите. Кроме того, дескрипторы базы данных должны иметь свои транзакции и затем закрываться, когда вы закончите с ними. Аналогично, если вы используете объектно-ориентированный язык, такой как C ++ или Objective C, не освобождая объект, когда вы закончите с ним, это означает, что деструктор никогда не будет вызван, и любые ресурсы, которые несет класс, могут не очиститься.
Вполне нормально оставлять память свободной при выходе; malloc () выделяет память из области памяти, называемой «кучей», и полная куча процесса освобождается, когда процесс завершается.
Как говорится, одна из причин, по которой люди все еще настаивают на том, что это чтобы освободить все до выхода, - это то, что отладчики памяти (например, valgrind on Linux) обнаруживают разблокированные блоки как утечки памяти, и если у вас также есть «настоящие» утечки памяти, становится сложнее их обнаружить, если вы также получаете «поддельные» результаты в конце.
free
в exit
время считается вредным.
– R..
29 January 2012 в 06:55
Если вы используете выделенную память, то вы не делаете ничего плохого. Это становится проблемой при написании функций (кроме основного), которые выделяют память без ее освобождения и не делают ее доступной для остальной части вашей программы. Затем ваша программа продолжает работать с выделенной ей памятью, но не использует ее. Ваша программа и другие запущенные программы лишены этой памяти.
Редактирование: на 100% невозможно сказать, что другие запущенные программы лишены этой памяти. Операционная система всегда позволяет им использовать ее за счет замены вашей программы на виртуальную память (</handwaving>
). Дело в том, что если ваша программа освобождает память, которую она не использует, смену виртуальной памяти с меньшей вероятностью необходимо.
Да, вы правы, ваш пример не наносит вреда (по крайней мере, не в большинстве современных операционных систем). Вся память, выделенная вашим процессом, будет восстановлена операционной системой после завершения процесса.
Источник: Распределение и мифы GC (оповещение PostScript!) [/ g2]
Миф о распределении 4: программы, не содержащие мусор, должны всегда освобождать всю память они выделяют.
Истина: пропущенные освобождения в часто исполняемом коде вызывают растущие утечки. Они редко приемлемы. но программы, которые сохраняют большую часть памяти, до выхода программы часто работают лучше без какого-либо промежуточного освобождения. Malloc намного проще реализовать, если нет свободного.
В большинстве случаев освобождение памяти непосредственно перед выходом программы бессмысленно. ОС все равно вернет его. Свободная воля коснется и занесет страницы в мертвые объекты; ОС не будет.
Следствие: будьте осторожны с «датчиками утечки», которые подсчитывают распределения. Некоторые «утечки» хороши!
blockquote>Тем не менее, вы действительно должны стараться избегать утечек памяти!
Второй вопрос: ваш дизайн в порядке. Если вам нужно что-то хранить, пока ваше приложение не выйдет, тогда это будет нормально, если вы используете динамическое распределение памяти. Если вы не знаете требуемый размер аванса, вы не можете использовать статически выделенную память.
Каков реальный результат здесь?
blockquote>Ваша программа просочилась в память. В зависимости от вашей ОС может быть восстановлен .
Большинство современных настольных операционных систем делают восстановление утечки памяти при завершении процесса, что делает ее грустным для проигнорируйте проблему, как видно из многих других ответов здесь.)
Но вы полагаетесь на функцию безопасности, на которую не следует полагаться, и ваша программа (или функция) может работать в системе, где это поведение делает в следующий раз «жесткой» утечкой памяти.
Возможно, вы работаете в режиме ядра или в винтажных / встроенных операционных системах, которые не используют защиту памяти как компромисс. (MMU занимают место в памяти, защита памяти требует дополнительных циклов процессора, и не так много, чтобы попросить программиста очистить после себя).
Вы можете использовать и повторно использовать память так, как вы например, убедитесь, что вы удалили все ресурсы до выхода.
Я полностью не согласен со всеми, кто говорит, что OP правильный или нет никакого вреда.
Все говорят о современной и / или устаревшей ОС.
Но что, если я ' m в среде, где у меня просто нет ОС? Где нет ничего?
Представьте, что теперь вы используете прерывания в стиле стилей и выделяете память. В стандарте C ISO / IEC: 9899 - это срок службы памяти, обозначенный как:
7.20.3 Функции управления памятью
1 Порядок и смежность памяти, выделенной последовательным вызовы функций calloc, malloc и realloc не определены. Указатель возвращается, если выделение успешно выполняется соответствующим образом, чтобы его можно было назначить указателю на любой тип объекта, а затем использовать для доступа к такому объекту или массиву таких объектов в выделенном пространстве (пока пространство явно не освобождено) , Время жизни выделенного объекта простирается от выделения до освобождения. [...]
blockquote>Поэтому не нужно указывать, что среда выполняет освобождающую работу для вас. В противном случае оно будет добавлено к последнему предложению: «Или до тех пор, пока программа не завершится».
Итак, другими словами: Не освобождение памяти - это не просто плохая практика. Он производит не переносимый, а не код соответствия. Который, по крайней мере, можно рассматривать как «правильный, если следующее: [...], поддерживается средой».
Но в тех случаях, когда у вас нет ОС вообще, никто не выполняет работу для вас (я знаю, как правило, вы не выделяете и не перераспределяете память на встроенные системы, но есть случаи, когда вы можете захотеть.)
Так что в общем случае обычный C (как отмечает OP) , это просто создает ошибочный и не переносимый код.
. Для этого есть несколько причин:
free()
реализации никогда не возвращают память в операционную систему. Что касается возможности будущего использования кода, оправдывая определенность бессмысленных операций: это соображение, но это, возможно, не способ Agile . YAGNI!
Если программа забывает освободить несколько мегабайт до того, как она выйдет из операционной системы, она освободит их. Но если ваша программа работает неделями, а цикл внутри программы забывает освободить несколько байтов на каждой итерации, у вас будет мощная утечка памяти, которая будет потреблять всю доступную память на вашем компьютере, если вы не перезагружаете ее на обычном basis => даже небольшие утечки памяти могут быть плохими, если программа используется для серьезной большой задачи, даже если она изначально не была предназначена для одного.
Нет реальной опасности , не освобождая ваши переменные, но если вы назначите указатель на блок памяти на другой блок памяти, не освобождая первый блок, первый блок больше не будет доступен но все равно занимает место. Это то, что называется утечкой памяти, и если вы сделаете это с регулярностью, то ваш процесс начнет потреблять все больше и больше памяти, отвлекая системные ресурсы от других процессов.
Если процесс недолговечен, часто удается избежать этого, поскольку вся выделенная память возвращается операционной системой, когда процесс завершается, но я бы посоветовал получить привычку освобождать всю память, для которой вы больше не пользуетесь.
Вы правы, память автоматически освобождается, когда процесс завершается. Некоторые люди стараются не проводить тщательную очистку, когда процесс завершается, так как все они будут оставлены в операционной системе. Однако, пока ваша программа работает, вы должны освободить неиспользуемую память. Если вы этого не сделаете, вы можете закончиться или вызвать чрезмерный пейджинг, если ваш рабочий набор становится слишком большим.
Я думаю, что ваши два примера на самом деле только один: free()
должен появиться только в конце процесса, который, как вы указываете, бесполезен, так как процесс завершается.
В вас второй пример, однако, единственное различие заключается в том, что вы разрешаете неопределенное число malloc()
, что может привести к нехватке памяти. Единственный способ справиться с ситуацией - проверить код возврата malloc()
и действовать соответственно.
Если вы разрабатываете приложение с нуля, вы можете сделать некоторые образованные выборы о том, когда звонить бесплатно. Ваша примерная программа в порядке: она выделяет память, возможно, у вас есть ее работа на несколько секунд, а затем закрывается, освобождая все ресурсы, которые она требовала.
Если вы пишете что-нибудь еще, сервер / долговременное приложение или библиотеку, которую должен использовать кто-то другой, вы должны ожидать бесплатного вызова всего, что вы malloc.
Игнорируя прагматическую сторону на секунду, гораздо безопаснее следовать строжайшему подход и заставить себя освободить все, что вы malloc. Если у вас нет привычки смотреть на утечки памяти, когда вы код, вы можете легко запустить несколько утечек. Так что, другими словами, да, вы можете обойтись без него; пожалуйста, будьте осторожны.
На самом деле есть раздел в онлайн-учебнике OSTEP для обучения студентов в операционных системах, в котором точно указан ваш вопрос.
Соответствующий раздел - «Забыть о свободной памяти» в в главе Memory API на стр. 6, которая дает следующее объяснение:
В некоторых случаях может показаться, что не вызов free () является разумным. Например, ваша программа недолговечна и скоро выйдет; в этом случае, когда процесс умирает, ОС очистит все выделенные страницы, и, таким образом, утечка памяти не произойдет сама по себе. Хотя это, безусловно, «работает» (см. в сторону на стр. 7 ), это, вероятно, плохая привычка развиваться, поэтому будьте осторожны в выборе такой стратегии
blockquote>. Этот фрагмент находится в контексте введения концепции виртуальной памяти. В основном на этом этапе книги авторы объясняют, что одной из целей операционной системы является «виртуализация памяти», то есть каждая программа считает, что она имеет доступ к очень большому адресному пространству памяти.
За кулисами операционная система будет переводить «виртуальные адреса», которые пользователь видит в фактических адресах, указывающих на физическую память.
Однако для совместного использования ресурсов, таких как физическая память, требуется, чтобы операционная система отслеживала о том, какие процессы используют его. Таким образом, если процесс завершается, то в рамках возможностей и целей разработки операционной системы восстанавливается память процесса, чтобы он мог распространять и делиться памятью с другими процессами.
EDIT: . Конец, упомянутый в выдержке, скопирован ниже.
ASIDE: ПОЧЕМУ НЕ УДАЛЕНА ПАМЯТЬ ПРОТИВ ПРОЦЕССА
Когда вы пишете короткий -lived, вы можете выделить некоторое пространство, используя
malloc()
. Программа запускается и собирается завершить: нужно лиfree()
вызвать кучу раз перед выходом? Хотя кажется неправильным, что никакая память не будет «потеряна» в каком-либо реальном смысле. Причина проста: в системе действительно два уровня управления памятью. Первый уровень управления памятью выполняется ОС, которая передает их в процессы, когда они запускаются, и возвращает их, когда процессы завершаются (или иначе умирают). Второй уровень управления находится внутри каждого процесса, например, внутри кучи, когда вы вызываетеmalloc()
иfree()
. Даже если вам не удалось вызватьfree()
(и, таким образом, удалить память в куче), операционная система восстановит всю память процесса (включая эти страницы для кода, стека и, в зависимости от ситуации, кучу), когда программа закончен. Независимо от того, каково состояние вашей кучи в вашем адресном пространстве, ОС возвращает все эти страницы, когда процесс умирает, тем самым гарантируя, что память не будет потеряна, несмотря на то, что вы ее не освободили.Таким образом, для недолговечных программ утечка памяти часто не вызывает никаких операционных проблем (хотя она может считаться плохой формой). Когда вы пишете долговременный сервер (например, веб-сервер или систему управления базами данных, которые никогда не выходят), утечка памяти является гораздо более серьезной проблемой и в конечном итоге приведет к сбою, когда в приложении закончится память. И, конечно, утечка памяти - еще более серьезная проблема внутри одной конкретной программы: самой операционной системы. Показывая нам еще раз: те, кто пишу код ядра, имеют самую сложную задачу для всех ...
из Страница 7 из Справочника по API главы
Операционные системы: три простых пьесы Ремзи Х. Арпачи-Дуссе и Андреа К. Арпачи-Дуссеу Книги Арпачи-Дуссо Март, 2015 г. (версия 0.90)
blockquote> blockquote>
Обычно я освобождаю каждый выделенный блок, как только я уверен, что с ним все закончится. Сегодня точкой входа моей программы может быть main(int argc, char *argv[])
, но завтра это может быть foo_entry_point(char **args, struct foo *f)
и введено как указатель функции.
Итак, если это произойдет, у меня теперь есть утечка.
Что касается вашего второго вопроса, если моя программа взяла ввод, например a = 5, я бы выделил место для a или перераспределял одно и то же пространство на следующем a = "foo". Это оставалось бы распределенным до:
Я не могу придумать никакой современной ОС, которая не восстанавливает память после выхода процесса. Опять же, free () дешево, почему бы не убрать? Как говорили другие, такие инструменты, как valgrind, отлично подходят для обнаружения утечек, о которых вам действительно нужно беспокоиться. Несмотря на то, что блоки, на которые вы, например, будете помечены как «все еще доступные», просто лишний шум в выходе, когда вы пытаетесь обеспечить отсутствие утечек.
Еще один миф: « Если его в main (), мне не нужно его освобождать ", это неверно. Рассмотрим следующее:
char *t;
for (i=0; i < 255; i++) {
t = strdup(foo->name);
let_strtok_eat_away_at(t);
}
Если это произошло до форкирования / демонтирования (и в теории работает вечно), ваша программа только что пропустила неопределенный размер в 255 раз.
Хорошая, хорошо написанная программа всегда должна очищаться после себя. Освободите всю память, очистите все файлы, закройте все дескрипторы, отсоедините все временные файлы и т. Д. Эта функция очистки должна быть достигнута при обычном завершении или при получении различных видов фатальных сигналов, если вы не захотите оставить некоторые файлы, лежащие вокруг, чтобы вы могли обнаружите сбой и возобновите.
На самом деле, будьте добры к бедной душе, которая должна поддерживать ваши вещи, когда вы переходите к другим вещам .. передайте их им «valgrind clean»:)
free() is cheap
, если у вас нет миллиарда структур данных со сложными отношениями, которые вы должны выпускать один за другим, перемещение структуры данных, чтобы попытаться выпустить все, может значительно увеличить время выключения, особенно если половина этой структуры данных уже выгружены на диск, без какой-либо выгоды.
– Lie Ryan
20 March 2013 в 02:37
=== Как насчет будущей проверки и повторного использования кода? ===
Если вы не пишете код, чтобы освобождать объекты, тогда вы ограничиваете использование кода только безопасным, если вы можете зависеть от свободной памяти в процессе, являющемся закрытые ... т. е. небольшие одноразовые проекты или «отбрасывающие» [1] проекты) ... где вы знаете, когда процесс закончится.
Если вы пишете код, свободный ( ) вся ваша динамически распределенная память, тогда вы будете в будущем проверять код и позволять другим использовать его в более крупном проекте.
[1] относительно проектов «выбросить». Код, используемый в проектах «Отбрасывание», имеет способ не выбрасываться. Следующее, что вы знаете, прошло десять лет, и ваш код «выкидывания» все еще используется).
Я слышал рассказ о каком-то парне, который написал какой-то код просто для удовольствия, чтобы улучшить его работу. Он сказал: « просто хобби, не будет большим и профессиональным ». Спустя годы многие люди используют свой «хобби» код.
malloc()
, если он есть, и завершает, если указатель все еще является нулевым, такую функцию можно безопасно использовать произвольным числом раз, даже если free
никогда не называется. Я думаю, что, вероятно, стоит различать утечки памяти, которые могут использовать неограниченное количество хранилищ, по сравнению с ситуациями, которые могут только тратить конечный и предсказуемый объем хранения.
– supercat
24 April 2018 в 18:46
null
, если распределение не существует и не имеет значения null, когда существует выделение, с кодом, освобождающим выделение и устанавливающим указатель на null
при уничтожении контекста, было бы просто, особенно по сравнению со всем остальным это необходимо сделать для перемещения статических объектов в структуру контекста.
– supercat
24 April 2018 в 21:08
Вы абсолютно правы в этом отношении. В небольших тривиальных программах, где переменная должна существовать до смерти программы, нет никакой реальной выгоды для освобождения памяти.
Фактически, я когда-то был вовлечен в проект, где каждое выполнение программы был очень сложным, но относительно недолговечным, и решение состояло в том, чтобы просто сохранить выделенную память и не дестабилизировать проект, сделав ошибки, освобождающие его.
В большинстве программ это не вариант, или это может привести к выходу из памяти.
Этот код, как правило, работает нормально, но рассмотрим проблему повторного использования кода.
Возможно, вы написали фрагмент кода, который не освобождает выделенную память, он запускается таким образом, что память затем автоматически исправляется. Кажется, все в порядке.
Затем кто-то копирует ваш фрагмент в свой проект таким образом, что он выполняется тысячу раз в секунду. У этого человека теперь есть огромная утечка памяти в его программе. Не очень хорошо в целом, обычно смертельно для серверного приложения.
Повторное использование кода типично для предприятий. Обычно компания владеет всем кодом, который производят его сотрудники, и каждый отдел может повторно использовать все, что принадлежит компании. Поэтому, написав такой «невинно выглядящий» код, вы вызываете потенциальную головную боль другим людям. Это может заставить вас уволить.