Comments 139
И еще вот это:
Топ хранится в std::list, где элементы — это указатели на объекты-биды. Один из коммитов привнес такой чудесный код для обрезания топа: list.resize(max_results). Как вы уже догадались, list.resize не вызывает delete на элементы-указатели. Нужно пройтись и ручками освободить память всех лишних указателей до вызова resize.У вас что, реально был list в котором лежали просто голые указатели? Даже не list unique_ptr-ов?
Проблема наступает когда не учитывается ownership объектов, куда они указывают (тут можно порекламировать Rust, но не будем). Нужно решить кто является овнером (на всё время жизни) и воткнуть туда unique_ptr, но если вообще ничего не понятно, и указатели прилетают то слева то справа, то можно обложить всё shared_ptr-ами, хотя тогда становится не ясен профит от использования плюсов, в таких случаях лучше уползти на java/c# ))
А лист голых указателей значит — «я тут написал код, который понимаю только я и только сейчас, модель владения объектами есть только у меня в голове и никому я её не расскажу».
В этом у манагед-языков как раз и профит. На плюсах мы будем постоянно ковырять общую кучу, что не так быстро. (либо придётся озаботиться арена-аллокаторами), а ГЦ потом просто соберёт весь этот хлам скопом, что обычно шустрее.
Вообще, сам по себе лист (или массив) голых указателей — не преступление.Вообще-то есть принципиальная разница между std::list с голыми указателями и std::vector с голыми указателями. Сложно придумать настолько же неэффективную структуру данных, как std::list для голых указателей. Сценарии, когда такое может потребоваться можно придумать (например, требуется сохранять валидность итераторов на элементы списка при модификации списка), но это очень уж редкие сценарии именно в сочетании с хранением голых указателей как элементов списка.
Подробности тут:
bannalia.blogspot.com/2014/05/fast-polymorphic-collections.html
www.boost.org/doc/libs/1_67_0/doc/html/poly_collection.html
Run on (1 X 3491.99 MHz CPU )
2018-04-27 11:49:10
— Benchmark Time CPU Iterations
— BM_list_smart 14538337425 ns 14505242000 ns 1
BM_vector_smart 11492866976 ns 11462727000 ns 1
BM_deque_smart 12638374021 ns 12605011000 ns 1
Дек не пробовал. Вообще стоит, конечно, пересмотреть все используемые структуры, коду 7 лет в обед…
Сортировка много раз в секунду? Эм, heap на векторе же. Хотя стандартный priority_queue, конечно, совершенно никчемный (как обычно) и не позволяет динамически менять вес элементов. Но сама структура данных позволяет это делать за O(log N), что явно быстрее полной сортировки.
Вектор обычно быстрее даже с учетом удаления из середины. Причем, быстрее на порядки. А вот необходимость сортировки, да еще и такой частой — как раз вопрос к структуре данных.
Сортировка необходима в аукционе, ответы приходят в произвольном порядке (каждый ответ содержит набор разных цен), и нужно либо сортировать при вставке (дорого), либо один раз в конце (наш вариант).
Я не хочу спорить с вашими "проигрывает", которые моими тестами не подтверждаются. Сортировать при вставке ничего не надо, если это вставка в heap (или изменение веса в нем же). Собственно, тут тоже спорить не о чем, если вы не понимаете, как и для чего работает heap, или же я не понял ваших задач.
10K запросов в кучу пихать не нужно, а вот если вы возьмёте priority_queue и будет хранть 100 лучших результатов, которые вам реально нужны — результат будет совсем другой.
Поделитесь более эффективным способом отсортировать большой массив структур более 10К раз в секунду?
Самый эффективный способ — не сортировать вовсе: попробуйте set/multiset. Можете также попробовать priority_queue
Run on (1 X 3491.99 MHz CPU )
2018-04-27 21:01:45
— Benchmark Time CPU Iterations
— BM_list_smart 14358524911 ns 14249840000 ns 1
BM_vector_smart 11455311425 ns 11442017000 ns 1
BM_set_smart 15602568549 ns 15579649000 ns 1
BM_pqueue_smart 12102934676 ns 12087128000 ns 1
Код — collabedit.com/4ex6s. Но, опять же, раньше там были вставки\удаления из произвольных позиций, с тех пор много чего поменялось, а «список» остался. Не знаю почему все кинулись оптимизировать этот код, было бы интереснее послушать про истории утечек в ЯВУ.
Но, опять же, раньше там были вставки\удаления из произвольных позиций, с тех пор много чего поменялось, а «список» остался
удаление из произвольной позиции list'а — O(N) поиск элемента и O(1) удаление. Удаление из произвольной позиции vector — O(1) поиск и O(N) удаление. У set поиск+удаление O(log(N)).
BM_vector_smart_ins_rm 15327045208 ns 15315396000 ns 1
BM_list_smart_ins_rm 21855116654 ns 21838877000 ns 1
Но с циклом рандомных вставок\удалений уже начинает отставать:
BM_vector_smart_ins_rm 30417423216 ns 30374146000 ns 1
BM_list_smart_ins_rm 29354732199 ns 29316292000 ns 1
В итоге к финишу они приходят одновременно.
Если честно, я потерял нить спора. Кто кому что пытается доказать?
list<unique_ptr<T>> 27598 ms
list<T> 24775 ms
vector 17061 ms
deque 17831 ms
set<unique_ptr<T>> 26980 ms
set<T> 26656 ms
priority_queue 15560 ms
list<unique_ptr<T>> ins/rm 20973 ms
list<T> ins/rm 16964 ms
vector ins/rm 14641 ms
finished
list<unique_ptr<T>> 33105 ms
list<T> 25850 ms
vector 20933 ms
deque 22210 ms
set<unique_ptr<T>> 26863 ms
set<T> 26618 ms
priority_queue 17046 ms
list<unique_ptr<T>> ins/rm 22084 ms
list<T> ins/rm 17485 ms
vector ins/rm 15120 ms
finished
Вы сортируете, а потом берете только 5 первых значений? Это же очень алгоритмически неэффективно. Смотрите std::partial_sort
(если порядок этих 5 элементов важен) либо std::nth_element
если нет. Если исходный список большой, то может иметь смысл использовать std::priority_queue.
Разница между двумя указателями и одним сильно меньше, чем между одним указателем и нулём указателей.
сложно было без замеров сказать, будет ли там быстрее vector/set/priority_queue, а вот замена list T* на list T дает гарантированный прирост
Надо смотреть на все случаи использования конкретной структуры данных и профилировать, иначе это тычки пальцем в небо.
Так я ж сразу писал: «попробуйте то, попробуйте это...». В теории set должен был быть выгоднее, но там кеш миссы подкосили.
Почему это не сортировать вовсе? Просто сортировка размазывается по всем вставкам, и последовательный доступ очень неэффективный (с точки зрения кеша, например).
да не совсем. Вставка N элементов в сет — N log(N). Сортировка — тоже, но сортировка (судя по всему) там проводится периодически, через каждые M вставок/удалений где M << N. Плюс у автора, как я понял, структуры данных побольше и эффективно не мувятся.
Как вы уже догадались, list.resize не вызывает delete на элементы-указатели.
Ну блин, как так можно? Плюнули на последние 10 лет прогресса С++ в плане управления памятью — вот вам и проблемы. Умные указатели вам в помощь.
Меня волнует другой вопрос — КАК у Вас получилось решать проблему утечку памяти не натолкнуться за эти 6 дней на санитайзеры? У меня по первой ссылке в поиске на SO есть реакомендация ASAN.
Расскажите насколько замедляется приложение при его использовании и какие есть подводные камни. Спасибо!
В C++ есть автоматическое управление памятью
Она явная, появляется, когда вы решите, что она вам нужна.
Как пример: std::shared_ptr/std::uniqure_ptr, placement new и move semantics
Ну, стандартные типы STL все довольно-таки безопасны. "Плоские" указатели в С++ — это не стандартная фича языка, а необходимое условие для совместимости с чистым Си.
не на контроллере а-ля stm32
C++ — язык для всего (в отличие от жабаскрипта, сисярпа, и жабы), поэтому навязывать прикладные подходы от настольного программирования не совсем правильно. К тому же С++ используется там, где традиционные подходы оказались непроизводительными и там действительно уже нужно явно контроллировать узкие места.
А вот про std::resize поверх std::list<T*> — это явный прокол, объясняющийся банальным непониманием работы стандартной библиотеки. Такие косяки допускаются в совершенно любом языке и их причина — не дизайн языка, а банальная невнимательность
что за такая странная любовь у мышей к пожиранию кактусов?
Это скорее стремление не городить велосипеды. C++ позволяет нативно сливаться в экстазе с Си, на котором написаны ядра операционных систем, системные библиотеки и прочие непотребности.
Писать любую обертку для "безопасного языка" — долго, сложно и неблагодарно. Кто хоть раз писал тысячу [DllImport] в дотнете, знает, как хочется просто за#includ'ить заголовочный файл нативной библиотеки
Это откровенный технический долг, за который платит клиент.
И С++ тут ни при чем, опять же. Утечку памяти можно сделать и в C#
Использование умного или намеренно тупого языка не освобождает от отвественности тестировать свой код
Безопасный язык и его приятный привкус.
Касаемо С++ стоит различать язык "до C++11" и после. То, что было раньше — треш и угар, хорошо, что тот "цэпэпэ" от нас почти ушел.
Современный C++11/14/17 по удобству очень похож на C#, разве что Linq нет и рефлексии (но рефлексией и в дотнете не так часто пользуются)
Ну в более новых языках типа раста есть вполне себе удобный bindgen. Кто-то там по-моему целый MySQL перегенерировал на расте. Не сказать, что безопасности написанного кода прибавилось, но вот работать уже с ним можно без извратов с «экстазом».
сам Роб Пайк, любитель всяких Си — сделал golangЗадолго до Golang-а, Роб Пайк сделал Limbo, в котором так же был GC.
В С++ программист всё ещё решает, нужно ли автоматическое управление память или нет.Именно это и делает C++ до сих пор востребованным.
хотя существуют исследования, доказывающие, что автоматическое управление памятью даже в плане производительности бывает заметно лучше, чем ручное управлениеЭти же исследования доказывают, что для достижения сравнимой производительности нужно иметь в четыре раза больше RAM, чем для такой же программы, но написанной на языке с ручным управлением памятью.
У меня на GCC в 400 килобайт поместилась полностью прошивка железки, в которой есть веб-сервер, telnet-консоль, драйверы периферии, поддержка файловых систем и вебморда с картинками (которая занимает половину из всего объема прошивки).
Так что про Hello World это громко.
Да, поддержка стандартной библиотеки неплохо раздувает код, но не настолько, как впиливание garbage collector в memory constrained платформу
Limbo широко использовался? Там что-то было принципиальное?Это не имеет значение. В контексте вашего высказывания о том, что «сам Роб Пайк, любитель всяких Си — сделал golang» важен сам факт того, что будучи «любителем Си», Пайк задолго до Golang сделал язык со сборкой мусора. После чего зачислять его в «любители Си» несколько странно.
Когда ко мне (в мою контору) приходят люди со знанием С++ они искренне недоумевают, почему мне такие специалисты не нужны.Чтобы говорить конкретно про вашу контору, нужно знать, что это за контора, чем она занимается и насколько успешно. Но здесь речь не об этом, а о том, что не смотря на то, что в большинстве случаев языки с GC успешно справляются, все равно есть ряд областей, где от GC больше вреда, чем пользы. И вот в таких областях чтобы отказаться от C++ и выбрать какую-нибудь Java, нужно иметь очень веские доводы (ну или альтернативный способ мышления). Насколько я слышал, он-лайн аукционы рекламы — как раз относятся к таким областям.
Да. И речь идёт про 250к+ памяти.Это вы не смейтесь, речь про приложения, в которых потребление памяти измерялась сотнями мегабайт, а сейчас уже и десятками гигабайт.
Comparing runtime, space consumption, and virtual memory footprints over a range of benchmarks, we show that the runtime performance of the best-performing garbage collector is competitive with explicit memory management when given enough memory. In particular, when garbage collection has five times as much memory as required, its runtime performance matches or slightly exceeds that of explicit memory management. However, garbage collection’s performance degrades substantially when it must use smaller heaps
Тут говорится, что приложение с GC будет показывать такую же или даже лучшую производительность, но ценой расхода дополнительной памяти. В частности, для достижения такой же производительности требуется в пять раз больше памяти.
На что ссылаетесь вы — хз. Впрочем, ереси вы здесь и так уже наговорили порядком.
Но вот что видно по расходу памяти по вашей же ссылке на Benchmark Game: Go потребляет меньше памяти в бенчмарках reverse-complement, fannkuch-redux, n-body, k-nucleotide. Все. Четыре случая из десяти.
На игрушечных примерах. Если ваши познания о накладных расходах на GC и ручное управление памятью базируются только на примерах из Benchmark Game, тогда ой. Спорить с вами невозможно.
Человек предлагает втыкать всюду проверки, где только можно.Проверки не заменяют тестов. Но вы этого, очевидно, еще не понимаете.
И после этого вы мне предъявляете, что я не читаю комментарии?Сможете дать точную цитату где я что-то подобное вам «предъявлял»?
Вы просили ссылку — я вам привёл ссылку. Где ваши ссылки?Актитесь, любезный, я вам дал ссылку на серьезное исследование, а не на маркетинговый булшит.
Проверки заменяют тест.От многократного повторения чепуха быть чепухой не перестанет.
Более того, тесты не проверяют логику.Не могу понять логику того, кто написал сей шедевр.
Тестер напишет тест так, как ему объяснил программист.Во-первых, не «тестер», а «тестировщик». Во-вторых, если у вас тестировщик пишет тесты со слов программиста, то с тестированием у вас такие же проблемы, как и с логикой.
Видимо, вы не писали с соблюдением контрактов.Да куда уж нам.
Моя программа уже 3 года на подстанции 110 кВ работает и ни одного падения.Аргумент, да.
ПожалуйстаДа уж, если это пример для «И после этого вы мне предъявляете, что я не читаю комментарии?», то мне остается только поинтересоваться «А с головой у вас все нормально?»
Вы, например, делаете допуск, что программист может получить неправильную спецификацию, может неправильно ее понять, могут быть неправильно написаны тесты. Но при этом вы не допускаете мысли о том, что с контрактами может быть все то же самое.
Это, в купе с другими вашими высказываниями, приводит меня к выводу, что конструктивного общения не получится из-за вашего альтернативного мышления. За сим прощаюсь. Жалею, что в очередной раз ввязался в разговор с вами.
Да, чтобы не оставлять повисших вопросов:
Покажите мне, где я написал «со слов программиста»?Вот ваши слова: «Тестер напишет тест так, как ему объяснил программист.» Дословно «со слов программиста» в вашей фразе нет, но я ее понял именно так.
GC не требует в четыре раза больше памяти, чем через руками. Это кусок рантайма.
важно не то, как работает сборка мусора, а как работает аллокатор в языках с GC. И если бы вы это знали, вы бы прекрасно понимали почему GC требует больше памяти. Это во-первых. Во-вторых, прикрутить (скажем) джавовский аллокатор вместо стандартного в плюсах можно. И если б он давал столь существенный прирост производительности, его б использовали повсеместно. В-третьих, обычно тесты c++ vs java/c# либо синтетические, либо откровенно плохо написаны. «std::list vs java array» — такое я уже видел.
Это наводит на мысли о не сильно высоком уровне квалификации. В таких условиях люди и на языке с GC наломают дров.
Лично я не вижу смысла писать тесты.Спасибо за
Пред и постусловия это прекрасно, но они тоже не все ловят. Эмерджентность во все поля, то, что каждый компонент работает правильно не гарантирует совместной корректной работы.
Что касается этой аргументации:
Если вы не читали всё обсуждение, я напишу ещё раз: С++ допустил утечку памяти. И не важно: были тесты, не было их… С++ допускает утечку памяти, а значит — память будет течь неизбежно. А тесты — либо написаны не были, либо тесты отработали кривую логику, кривого алгоритма.
Это из разряда «сгорел сарай — гори и хата» и «чего мыться — все равно через неделю испачкаюсь».
Изначальную порочность С++ вы еще не доказали.
И соответственно первые — это Java, .NET, тот же компонентный Паскаль и Оберон, если верить агитаторам за них в этом треде, а второй — C++, потому что в нём даже ряд стандартных интерфейсов используют указатели, и просто факт использования указателя никак не означает опасного использования (а значит — поиск факта некорректного использования значительно усложняется).
То, что коллега prospero78su не может это сформулировать корректным образом — вопрос его дискуссионного стиля, а не самого факта. Этот комментарий это хорошо подтверждает. И мне не нравится, что вместо понимания сути того, что он говорит, оппоненты лезут в бутылку (а кто-то явно даже карму минусует).
Этот комментарий это хорошо подтверждает.Что именно он подтверждает? Что «коллега prospero78su» несёт чушь, рассуждая о вещах, о которых он понятия не имеет?
Ну посмотрите на этот ваш «великолепный» комментарий предложение за предложением.
В Компонентном Паскале — не бывает указателей, у которых можно свернуть башку.Обычые указатели там, несоменного бывают. А чем «указатель у которого сожно свернуть башку» отличается от «указателя у которого башку свернуть нельзя» — науке неведомо.
Или нечаянно — изменить тип.Рекомедую коллеге глубжее изучить язык о котором он говорит и обнаружить для себя тип
ANYPTR
.Динамических массивов в Компонентном Паскале нет, именно по этой причине.Динамических массивов нет — а вот открытые массивы — вполне себе есть. Для организации совершенно замечательных утечек памяти — их вполне достаточно.
Память в нём — не течёт. Вообще. Никак. Никогда.Чушь, ложь, враки. Как в любом другом языке с динамическеской памятью утечки вполне типичны.
Ну и? Чего осталось для обсуждения?
И мне не нравится, что вместо понимания сути того, что он говорит, оппоненты лезут в бутылку (а кто-то явно даже карму минусует).В бутылку тут лезете только вы с вашим «уважаемым» коллегой.
Я вполне понимаю его аргумент в том смысле, что есть языки/рантаймы, в которых, чтобы получить утечки памяти, доступ по некорректным адресам, нарушение структуры кучи и т.п. — надо использовать какие-то явно названные средстваOk, принято. Рассмотрим языки где утечки памяти требуют специальных конструкций и языки, где это не так.
В первую группу попадут Brainfuck, Malbolge и прочая разная эзотерика. Из мейнстриймовых языков сюда попадут разве что GW-BASIC и FBD. Ни Java, ни C#, ни Oberon, ни Component Pascal — даже рядом не валялись.
И соответственно первые — это Java, .NET, тот же компонентный Паскаль и Оберон, если верить агитаторам за них в этом треде, а второй — C++Серьёзно? Вы всерьёз хотите сказать, что не можете написать программу, в которой будет утекать память на всех этих языках? Это больше характеризует вас, а не языки, извините.
Утечки памяти — фактически неизбежное следствие достижения язком определённого уровня выразительности. Cобственно любой язык, умеющий оперировать с данными заранее неизвестного объёма их имеет.
Будь то Lisp, Prolog, C# или Component Pascal — неважно. Либо у вас память распределяется во время компиляции программы (и тогда утечек нет по определению), либо — в рантайме (и тогда они рано или поздно появятся).
А вот всё остально, что вы хотите «до кучи» доложить — это да… но это уже совсем другая история.
С тем, что C# безопаснее C++ — никто не спорит. Но, вы уж извините, статья — она как бы про утечки памяти. И вся дискуссия — тоже о них. И вот с ними в Component Pascal и Java — всё также, как и в C++, увы: да, они возможны и нет, это не теоретическая возможность.
Без unsafe и в том же понимании утечки — нет, не могу. И это «характеризует» каждого.
Я тут не считаю ту утечку, которая в managed-среде от забытых ссылок на живые объекты. Для такой ситуации можно, хоть и дороже, найти эти объекты и проанализировать ситуацию точными штатными средствами (откуда эти ссылки, которые их держат, с точностью до объекта и его поля, и т.п.), а главное — корректность кучи не нарушена, данные не перезатёрты, не требуется дорогой учёт предыстории. Для неуправляемой памяти таких средств нет, и начинаются всякие сложные косвенные анализы.
> Рекомедую коллеге глубжее изучить язык о котором он говорит и обнаружить для себя тип ANYPTR.
Про Паскаль я сделал явно оговорку, что тут верю ему на слово — не зная, какая конкретно версия у него использовалась и в каком режиме. Если он не может не использовать тот же anyptr, или как там он зовётся у него, и не может ограничить его использование специальными анклавами — то да, у него нет преимуществ.
> Но, вы уж извините, статья — она как бы про утечки памяти.
А ветка обсуждения — скорее про термины. Я понял, о каких утечках в каком смысле он говорит, а остальные, похоже, даже не попытались.
По поводу отката на старые версии — вся первая часть статьи посвящена этому вопросу, а почему не обнаружили — в конце.
Тесты, способные сымитировать похожую нагрузку и ответы (и при этом еще и за памятью правильно следить) требуют минимум х2 в инфраструктуру серверов и разработку (и то никаких гарантий обнаружения подобных утечек).Есть ощущение, что и по поводу тестирования приложений (особенно тех, которые затем должны работать в режиме 24/7, да еще и в такой специфической области) у вас такие же заблуждения, как и в отношении стоимости использования unique_ptr.
Посмотрите на современные инструменты. Например, мы для автотестов C++ кода используем набор из Gitlab CI + ASAN + TSAN + gcov + gtest + gbenchmark.
Если проект большой и давно живет, а автотестов в нем нет совсем, то дешевле всего его обмазать внешними, тестами — они позволяют приложив минимум усилий, дать максимум уверенности, что все работает так как надо. (следующий шаг это unit тесты c gtest/gbenchmark, они дадут более информативную диагностику, но их внедрить сильно дороже)
Объем инфраструктуры который требуется:
- виртуалка(-и) для Gitlab (наверняка у вас уже есть)
- виртуалка(-и) для запуска GitLab CI runner-ов
Для небольших команд ~10 человек — вся эта инфраструктура спокойно влезет на 2 виртуалки работающие на 1-м физическом сервере.
Общий подход примерно такой:
- в билд системе добавляете target-ы для сборки нескольких вариаций инструментированного бинаря:
- Делаете набор мок сервисов (например, на том же python, изображающих реальные сервисы, с которыми работает ваше ПО).
- Делаете тестовое приложение, которое изображает из себя клиента, и содержит набор тест кейсов (типа в такой то — последовательности сходить в методы API тестируемого ПО/и проверить результаты). В качестве инструмента подойдет тот же python, для него есть ряд фреймворков для этой задачи.
- В gitlab-ci добавляете pipeline тестов, в которых рядом запускаются мок сервисы+тестируемое ПО+в том же раннере запускаете по очереди тест кейсы.
- По завершению тестов шлете приложению SIGTERM.
Конечно, шаги 2) и 3) потребуют вложить заметное количество усилий, но они себя очень быстро окупят.
Что имеем на выходе:
1) проверка что, ничего не утекло (после выхода бинарь инструментировнный ASAN выдаст список того, что утекло)
2) убедимся, что не было рейсов (TSAN сборка в этом поможет)
3) сможем посмотреть глазами, какой процент кода оказался покрыт нашими тестами (gcov инструментарий даст общий % покрытия и подробный репорт, и покажет в какие строчки попадало управление, а в какие нет). На основании этой информации расширяете покрытие тестами.
И это все работает в весьма скромной аппаратной инфраструктуре.
Автору спасибо за познавательный обзор отладочных инструментов.
По поводу HEAPPROFILE — понятно что не будет работать только с ним, «либо\либо» — это оговорка в статье.
Опять же, вокруг C++ много мифов. Которые, зачастую, рождаются в результате вот таких вот случаев. Одни «профи» отказались от помощи со стороны языка (RAII, unique_ptr) и выбрали для своих задач откровенно неэффективные структуры данных (все-таки std::list для хранения всего лишь указателей — это жуткий перерасход памяти + добавление лишнего уровня косвенности при обращении к элементам, тут уж если нужны были именно свойства list-а, то следовало бы смотреть в сторону интрузивного двухсвязного списка). А потом, когда жопа таки случается, не знают за что хвататься. Другие «профи» прочитают такой отчет о закономерно полученных проблемах и делают для себя вывод о том, что C++ — это отстой
По существу, про C++ все так и есть. По форме — имхо стоит быть терпимее к просчетам других людей.
В разработке ПО же когда случается какая-то беда, почему-то начинаются разговоры про «токсичность и высокомерие» или «стоит быть терпимее к просчетам других людей». Вся обсуждаемая здесь статья — это яркий пример того, как делать не нужно. О чем и следует говорить.
Доля истины в ваших словах есть. Но идеальных людей нет. Нет и идеальных специалистов. С++ — язык который я пронес через 20 лет, это мой первый серьёзный язык, который я учил. Поэтому я мыслил как С++ когда писал программы. Прошли годы и я изучил несколько других концепций в языках программирования. Сейчас, на сегодняшнем уровне своего развития я пришел к пониманию того, что для того чтобы писать код на с++, нужно хорошо выспаться, сделать зарядку, помедитировать, настроится и сконцентрироваться, потом в том состоянии познания дзен быстро кодить, пока вдохновение не ушло. Вовремя остановиться. Рано лечь спать. С++ очень крут, но требует предельной концентрации и всеобъемлющего понимания кода. Сегодня для своих нужд я пришел к языку Ada (не реклама). Я для себя понял, что я точно не робот кодить без ошибок. Компилятор должен облегчать жизнь программистам, ВЕЗДЕ где возможно. Везде идет процесс унификации. Супер спецов всегда будет не хватать, а потребность в софте будет расти. Поэтому инструменты разработки будут развиваться таким путем, чтобы даже средний по уровню специалист писал приемлемый код. Я врач, за последние 20 лет хирургия превратилась из искусства в ремесло (и это нормально). То что раньше мог делать отдельный одаренный Кулибин, сегодня при помощи нового инструмента делает почти любой (Да, Кулибиных в медицине тоже мало). У C++ концептуально с этим трудности. Но ему придется измениться! В первую очередь наверное отказаться от совместимости с С.
Просматривается максимализм. В конкретной моменте с std::list и сырыми указателями, я с вами конечно согласен. Результат закономерен. Как выбирался инструмент программирования, мы не знаем. Может заставляли, может нет. Может автор на тот момент только С++ знал. Использовал то, что знал. Тех задание часто меняется по ходу дела, если оно вообще было. Автор поделился честным опытом, за что ему спасибо. А бывают ситуации, когда тебя ставят перед фактом для тебя мало изученной темы и требуют результат. А так, типа- "Эй… эй… Пацаны. Да вы здесь неочень...", выглядит не солидно. Вот вы тоже пишите статьи и многие благодарны вам за это, и я в их числе, хороший стиль, с удовольствием читаю.
Просматривается максимализм.Боюсь, что то, что вы принимаете за максимализм, это лишь следствие многолетних наблюдений, когда люди с завидным постоянством наступают на одни и те же грабли.
Это обычный человек увидя последствия ДТП, когда пешеход в нарушение правил ППД выбежал на дорогу и попал под машину, может охать, ахать и причитать «да как же так, да кто же мог подумать». А немолодой сотрудник ГАИ или врач скорой с многолетним опытом отнесется к произошедшему, думаю, совсем иначе. Собственно, у меня такая же профдеформация.
Автор поделился честным опытом, за что ему спасибоДа, автор поделился. За это ему спасибо. Но написанное в итоге следует воспринимать как горький урок. И ценность статьи, как мне кажется, вовсе не в перечне инструментов, с которыми автору довелось познакомиться. А именно в том, что здесь идет наглядная демонстрация: нарушил правила — отгреб по полной программе.
Поэтому я не понимаю комментариев вот такого вида. Из-за чего эта подветка обсуждения и появилась.
Просматривается максимализм.
Кто виноват в том, что абстрактная программа работает некорректно — её автор или ЯП, на котором она написана?
Про tcmalloc:
В комплекте с pprof это очень мощный инструмент, который позволяет прямо в RUNTIME в любой момент следить за всей памятью выделенной приложением, даже tcmalloc на вашем хосте не умеет leak detection.
Выглядит как то так:
pprof --inuse_objects http://127.0.0.1:9088/debug/pprof/heap
Using remote profile at http://127.0.0.1:9088/debug/pprof/heap.
Fetching /pprof/heap profile from http://127.0.0.1:9088/debug/pprof/heap to
/Users/ogerasimov/pprof/reindexer_server.1524898743.127.0.0.1.pprof.heap
Wrote profile to /Users/ogerasimov/pprof/reindexer_server.1524898743.127.0.0.1.pprof.heap
Welcome to pprof! For help, type 'help'.
(pprof) top
Total: 976926 objects
269535 27.6% 27.6% 446325 45.7% reindexer::IndexUnordered::Upsert
263687 27.0% 54.6% 263687 27.0% reindexer::make_key_string
139063 14.2% 68.8% 139063 14.2% __hash_table::__construct_node_hash
138999 14.2% 83.0% 138999 14.2% reindexer::PayloadValue::PayloadValue
110115 11.3% 94.3% 330296 33.8% reindexer::IndexStore::Upsert
35548 3.6% 98.0% 37827 3.9% btree::btree::rebalance_or_split
11212 1.1% 99.1% 11212 1.1% reindexer::h_vector::reserve
1041 0.1% 99.2% 39690 4.1% btree::btree::internal_insert
1008 0.1% 99.3% 28663 2.9% reindexer::IdSet::Add
960 0.1% 99.4% 960 0.1% leveldb::::HandleTable::Resize
Что бы это работало, в свое приложение надо добавить весьма тривиальную обработку вызова нескольких http методов для pprof
deleted
Про утечку памяти в одном серверном приложении