Чому такі мови, як C і C ++, не збирають сміття, а Java? [зачинено]


57

Ну, я знаю, що є такі речі, як malloc / free для C та new / using-a-destructor для управління пам’яттю в C ++, але мені було цікаво, чому не існує «нових оновлень» цих мов, які дозволяють користувачу є можливість вручну керувати пам’яттю або система робить це автоматично (вивезення сміття)?

Якесь питання для новачків, але лише в КС близько року.


9
У цьому семестрі у нас є модуль з розробки iPhone. Після кодування програм для Android протягом 2 років це питання вразило більшість класу досить сильно. Тільки тепер ми бачимо, скільки годин насправді Java врятувала, не маючи відслідковувати неприємні помилки управління пам’яттю та не потрібно писати код пластини котла.
siamii

7
@NullUserException, оскільки він не визначає спосіб відновлення пам'яті, що в значній мірі передбачає GC.
Вінстон Еверт

1
@ bizso09: Ви ще дивилися ARC? Немає необхідності у повільному / жировому / недетермінованому GC, коли у вас є підтримка системи для підрахунку посилань: developer.apple.com/technologies/ios5
JBRWilkinson

3
Відповіді на це досить гарне запитання сповнені релігійних дурниць.
абатищев

1
У C і C ++ можна взяти покажчик, віддати його до int та додати до нього число. Пізніше піднесіть число з int та відкиньте результат назад до вказівника. Ви отримаєте той же покажчик, що і раніше. Удачі в застосуванні GC, який НЕ збирає цю пам'ять, тоді як її адреса зберігається лише у змінній, яка також має інше значення. Я знаю, що приклад нерозумний, але список, пов'язаний з XOR, використовує щось подібне. Я б написав це як відповідь, але питання закрите.
Маріан Спаник

Відповіді:


71

Для збору сміття потрібні структури даних для відстеження розподілу та / або підрахунку довідок. Вони створюють накладні витрати на пам’ять, продуктивність та складність мови. C ++ розроблений так, щоб він був "близьким до металу", іншими словами, він займає більш високу продуктивність функцій компромісу проти зручності. Інші мови роблять цей компроміс інакше. Це одне з міркувань при виборі мови, якому наголос ви віддаєте перевагу.

Однак, існує багато схем для підрахунку посилань на C ++, які є досить легкими та ефективними, але вони є в бібліотеках, як комерційних, так і з відкритим кодом, а не частиною самої мови. Підрахунок посилань для управління терміном експлуатації об'єкта не є таким же, як збирання сміття, але він вирішує багато однакових питань і краще відповідає основним підходам C ++.


26
Вторинним питанням є те, що GC є недетермінованим. Об'єкт може або не може залишатися в пам'яті довгий час після того, як програма його "скинула". Життєві цикли знижок детерміновані, коли остання посилання падає, пам'ять падає. Це має значення не тільки для ефективності пам'яті, але і для налагодження. Поширеною помилкою програмування є об'єкт "зомбі", опорна пам'ять, яка теоретично була скинута. GC набагато більше шансів замаскувати цей ефект і створити помилки, які переривчасті і надзвичайно важко відстежити.
kylben

22
- сучасні gc не виділяють ні доріжок, ні посилань. Вони будують графік з усього, що зараз знаходиться на стеці, і просто конденсують і стирають все інше (спрощено), а GC зазвичай призводить до зниження складності мови. Навіть користь від ефективності сумнівна.
Joel Coehoorn

13
Е, @kylben, вся суть автоматичного використання GC в мові полягає в тому, що неможливо посилатися на зомбі-об'єкти, оскільки GC звільняє лише ті об'єкти, на які неможливо посилатися! Ви отримуєте такі важкі помилки, про які ви говорите, коли помиляєтесь при ручному керуванні пам'яттю.
Бен

14
-1, GC не враховує посилання. Плюс до цього, залежно від схеми використання та розподілення пам’яті, GC може бути швидшим (із накладними витратами на використання пам'яті). Тож аргумент щодо продуктивності теж є помилковим. Тільки близька до металу фактично є дійсною точкою.
deadalnix

14
Ні Java, ні C # не використовують підрахунок посилань: схеми GC, засновані на підрахунку посилань, є досить примітивними порівняно і працюють набагато гірше, ніж сучасні збирачі сміття (головним чином, тому, що їм потрібно робити пам'ять, щоб змінювати підрахунки довідок, коли ви копіюєте посилання!)
mikera

44

Власне кажучи, на мові С взагалі немає керування пам'яттю. malloc () та free () - це не ключові слова в мові, а лише функції, які викликаються з бібліотеки. Ця відмінність може бути педантичною зараз, тому що malloc () та free () є частиною стандартної бібліотеки C і забезпечуватимуться будь-якою стандартною реалізацією C, але це не завжди було вірно.

Чому ви хочете мову, яка не має стандарту для управління пам’яттю? Це повертається до витоків С як "переносна збірка". Існує багато випадків апаратних та алгоритмів, які можуть отримати користь або навіть вимагати спеціалізованих методів управління пам'яттю. Наскільки я знаю, немає способу повністю відключити управління рідною пам'яттю Java та замінити її на власну. Це просто не прийнятно в деяких ситуаціях з високою продуктивністю / мінімальними ресурсами. C забезпечує майже повну гнучкість у виборі саме тієї інфраструктури, яку використовуватиме ваша програма. Платна ціна полягає в тому, що мова С надає дуже мало допомоги в написанні правильного коду, що не відповідає помилкам.


2
+1 один за загальну хорошу відповідь, але також особливо за "Платна ціна полягає в тому, що мова C надає дуже малу допомогу в написанні правильного коду без помилок"
Shivan Dragon

2
У C є управління пам'яттю - але воно просто працює, тому люди ледве помічають його. Є статична пам'ять, регістри та стек. Поки ви не почнете виділяти з купи, у вас все добре і денді. Це розподіл купи псує речі. Що стосується Java, кожен може написати власний час виконання Java - є з чого вибрати, включаючи те, що можна назвати "Ява системи". .NET може зробити майже все, що може C - він лише відстає від власних можливостей C ++ (наприклад, класами керують лише в .NET). Звичайно, у вас також є C ++. NET, в якому є все, що робить C ++, і все .NET робить.
Луань

1
@Luaan Я б сказав, що це дуже щедре визначення "управління пам’яттю" "Доки ви не почнете виділяти з купи, ви добре і дэнді. Це розподіл купи псує речі", це як сказати, що машина - це ідеально хороший літак, він просто не в змозі літати.
Чарльз Е. Грант

1
@ CharlesE.Grant Добре функціональна мова може робити все з таким управлінням пам'яттю. Тільки тому, що розподіл купи - це хороша компроміс у деяких випадках використання, не означає, що це орієнтир для всіх мов / час виконання. Це не так, як управління пам’яттю перестає бути «управлінням пам’яттю» лише тому, що це просто, прямо-прямо, приховано за лаштунками. Проектування статичного розподілу пам’яті все ще керує пам’яттю, як і добре використовувати стек і все, що у вас є.
Луань

"будь-яка стандартна сумісна реалізація" не відповідає дійсності, лише для впровадження стандартної середовищі хост-середовища. Деякі платформи / стандартні бібліотеки, більшість для 8 чи 16-бітового вбудованого мікроконтролера, не надають malloc()або free(). (наприклад, MLAP-компілятори для PIC)
12431234123412341234123

32

Справжня відповідь полягає в тому, що єдиний спосіб зробити безпечний ефективний механізм збору сміття - це підтримка на рівні мови непрозорих посилань. (Або, навпаки, відсутність підтримки на рівні мови для прямого маніпулювання пам'яттю.)

Java та C # можуть це робити, оскільки вони мають спеціальні типи довідок, якими не можна керувати. Це дає свободі виконання часу робити такі речі, як переміщення виділених об'єктів у пам'ять , що є вирішальним значенням для високоефективної реалізації GC.

Для запису жодна сучасна реалізація GC не використовує підрахунок посилань , так що це абсолютно червона оселедець. Сучасні ГК використовують колекцію поколінь, де нові виділення трактуються по суті так само, як виділення стека є такою мовою, як C ++, а періодично будь-які новопризначені об'єкти, які ще живі, переміщуються в окремий простір "виживця" та ціле покоління об'єктів розміщується відразу.

Цей підхід має плюси і мінуси: перевага полягає в тому, що купірування виділень на мові, яка підтримує GC, настільки ж швидко, як і розподіл стеків мовою, яка не підтримує GC, і недоліком є ​​те, що об'єкти, які потребують очищення, перш ніж знищити потрібен окремий механізм (наприклад, usingключове слово C # ), інакше їх код очищення працює недетерміновано.

Зауважте, що одним із ключових моментів у високоефективній GC є те, що для спеціальної категорії посилань повинна бути підтримка мови. C не має такої мовної підтримки і ніколи не буде; оскільки C ++ має перевантаження оператора, він може імітувати тип вказівника GC, хоча це потрібно робити обережно. Насправді, коли Microsoft винайшла свій діалект C ++, який би працював під CLR (.NET час виконання), їм довелося винайти новий синтаксис для "C # -style reference" (наприклад Foo^), щоб відрізнити їх від "C ++ - посилань на стиль" (наприклад Foo&).

Що C ++ має, а що регулярно використовується програмістами C ++, це розумні покажчики , які насправді є лише механізмом підрахунку довідок. Я б не вважав підрахунок посилань "справжнім" GC, але він надає багато таких же переваг, ціною більш повільної продуктивності, ніж ручне управління пам'яттю або справжній GC, але з перевагою детермінованого знищення.

Зрештою, відповідь дійсно зводиться до функції дизайну мови. C зробив один вибір, C ++ зробив вибір, який дозволив йому бути сумісним назад із C, в той же час надаючи альтернативи, які є досить хорошими для більшості цілей, а Java та C # зробили інший вибір, несумісний із C, але також досить хороший для більшість цілей. На жаль, срібної кулі немає, але ознайомлення з різними варіантами допоможе вам вибрати правильну програму для будь-якої програми, яку ви зараз намагаєтеся створити.


4
Це фактична відповідь на питання
coredump

1
Що стосується частини c ++, то сьогодні варто подивитися на std :: unique_ptr та std :: move :)
Ніклас Ларссон,

@NiclasLarsson: Я не впевнений, що розумію вашу думку. Ви говорите, що std::unique_ptrце "підтримка на мовному рівні для непрозорих посилань"? (Це не така підтримка, яку я мав на увазі, і я також не думаю, що це достатньо, якщо підтримка прямого маніпулювання пам'яттю також не була видалена з C ++.) Я в своїй відповіді згадую розумні покажчики, і я вважаю std:unique_ptrрозумний покажчик , оскільки він насправді робить підрахунок посилань, він просто підтримує лише спеціальні випадки, коли кількість посилань дорівнює нулю або одиниці (і std::moveє механізмом оновлення відліку посилань).
Даніель Приден

std::unique_ptrне має підрахунку довідок і std::moveвзагалі не має нічого спільного з посиланнями (тому показник "не"). Я бачу вашу думку, як std::shared_ptrі чисельність посилань, що непрямість оновлено std::move:)
Ніклас Ларссон

2
@ Mike76: З боку розподілу, розподільник GC працюватиме так само швидко, як і розподіл стеків, і GC може одночасно розміщувати тисячі об'єктів. Незалежно від того, що ви робите з реалізацією повторного підрахунку, розподіл та розміщення ніколи не будуть швидшими за mallocта free. Так що так, GC може бути значно швидшим. (Зверніть увагу, що я сказав "можна" - звичайно, на точну ефективність кожної програми впливає багато факторів.)
Даніель Приден

27

Тому що, використовуючи потужність C ++, немає потреби.

Герб Саттер: " Я не писав видалення за роки ".

див. Написання сучасного коду C ++: як розвивався C ++ протягом 21:10

Це може здивувати багатьох досвідчених програмістів на C ++.


Цікаво. Мій матеріал для читання на сьогодні.
surfasb

Ба, відео. Але ніколи менш цікавого вже.
surfasb

2
цікаве відео. На 21 хвилині та 55 хвилинах пішли найкращі шматки. Шкода, що виклики WinRT все ще виглядали як C ++ / CLI bumpf.
gbjbaanb

2
@ dan04: Це правда. Але тоді, якщо ви пишете на С, ви отримуєте те, що просите.
DeadMG

6
Керування розумними покажчиками не є більш вимогливим, ніж гарантувати, що у вас немає зайвих посилань у сміттєвому середовищі. Оскільки GC не може прочитати вашу думку, це теж не магія.
Tamás Szelei

15

"Все" збирач сміття - це процес, який періодично запускає перевірку, чи є в пам'яті якісь нерозв'язані об'єкти та чи є їх видалення. (Так, я знаю, що це грубе спрощення). Це не властивість мови, а рамки.

Є збирачі сміття , написані для C і C ++ - це одне , наприклад.

Однією з причин того, що ніхто не був "доданий" до мови, може бути той самий об'єм існуючого коду, який ніколи не буде використовувати його, оскільки вони використовують власний код для управління пам'яттю. Ще одна причина може полягати в тому, що типи додатків, написаних на C і C ++, не потребують накладних витрат, пов'язаних з процесом збору сміття.


1
Але майбутні програми, які будуть написані, почнуть використовувати сміттєзбірник, ні?
Темний тамплієр

5
Хоча збір сміття теоретично не залежить від будь-якої мови програмування, досить складно написати корисний GC для C / C ++, і навіть неможливо зробити дурний доказ (принаймні настільки нерозумний, як Java) - причина, по якій Java може це витягнути вимикається тому, що він працює в контрольованому віртуалізованому середовищі. І навпаки, мова Java розроблена для GC, і вам буде важко писати компілятор Java, який не робить GC.
tdammers

4
@tdammers: Я погоджуюся, що збирання сміття потрібно підтримувати мовою, щоб це було можливо. Однак головним моментом є не віртуалізація та контрольоване середовище, а суворе введення тексту. C і C ++ слабо набрані, тому вони дозволяють такі речі, як зберігання покажчика в цілій змінній, реконструкція покажчиків від зсувів і такі речі, які заважають колектору бути в змозі надійно сказати, що можна досягти (C ++ 11 забороняє пізніше дозволяти принаймні консервативні колекціонери). У Java ви завжди знаєте, що таке посилання, тож ви можете точно зібрати його, навіть якщо складено на рідну мову.
Ян Худек

2
@ ThorbjørnRavnAndersen: Я можу написати дійсну програму C, яка зберігає покажчики таким чином, що жоден збирач сміття не міг їх знайти. Якщо потім підключити до смітника mallocі free, ви порушите мою правильну програму.
Бен Войгт

2
@ ThorbjørnRavnAndersen: Ні, я б не телефонував, freeпоки не закінчився. Але запропонований вами сміттєзбірник, який не звільняє пам'ять, доки я явно не закликаю, freeвзагалі не є сміттєзбірником.
Бен Войгт

12

C був розроблений в епоху, коли збирання сміття ледве було можливим. Він також був призначений для використання, коли збирання сміття зазвичай не працює - голий метал, середовище в режимі реального часу з мінімальною пам’яттю та мінімальною підтримкою для виконання. Пам'ятайте, що C була мовою реалізації першого unix, який працював на pdp-11 з 64 * К * байтами пам'яті. Спочатку C ++ був розширенням на C - вибір вже зроблений, і збирати сміття на важко існуючу мову дуже важко. Це та річ, яку потрібно вбудувати з першого поверху.


9

У мене немає точних цитат, але і Bjarne, і Herb Sutter щось говорять:

C ++ не потребує сміттєзбірнику, оскільки він не має сміття.

У сучасному C ++ ви використовуєте розумні покажчики і тому не має сміття.


1
що таке розумні покажчики?
Темний тамплієр

11
якби це було так просто, ніхто не втілив би жоден GC.
deadalnix

7
@deadalnix: Правильно, тому що ніхто ніколи не реалізує щось надмірно складне, повільне, роздуте або непотрібне. Все програмне забезпечення є на 100% ефективним весь час, правда?
Зак

5
@deadalnix - C ++ підхід до управління пам’яттю новіший, ніж сміттєзбірники. RAII був винайдений Bjarne Stroustrup для C ++. Очищення деструкторів - це стара ідея, але правила забезпечення безпеки виключень є ключовими. Я не знаю, коли саме тоді вперше була описана сама ідея, але перший стандарт C ++ був доопрацьований у 1998 році, а Stroustrups "Design and Evolution of C ++" був опублікований до 1994 року, і винятки були відносно недавнім доповненням до C ++ - після публікації "Повідомлення з анотацією на C ++" у 1990 році, я вважаю. GC була винайдена в 1959 році для Lisp.
Стів314

1
@deadalnix - чи знаєте ви, що принаймні один Java VM використовував GC-підрахунок посилань, який можна (майже) реалізувати за допомогою RAII у стилі C ++, використовуючи клас інтелектуального вказівника - саме тому, що він був більш ефективним для багатопотокового коду, ніж існуючі VM? Дивіться www.research.ibm.com/people/d/dfb/papers/Bacon01Concurrent.pdf. Однією з причин того, що ви не бачите цього в C ++ на практиці, є звичайна колекція GC - вона може збирати цикли, але не може вибрати безпечний порядок деструкторів за наявності циклів, а отже, не може забезпечити надійне очищення деструктора.
Стів314

8

Ви запитуєте, чому ці мови не оновлювались, щоб включити необов'язковий збирач сміття.

Проблема з необов'язковим збиранням сміття полягає в тому, що ви не можете змішувати код, який використовує різні моделі. Тобто, якщо я пишу код, який передбачає, що ви використовуєте сміттєзбірник, ви не можете використовувати його у своїй програмі, де вимкнено сміття. Якщо ви це зробите, він просочиться скрізь.


6

Ви можете уявити, як писати обробник пристрою мовою зі збиранням сміття? Скільки бітів могло зійти вниз, коли GC працював?

Або операційна система? Як ви могли запустити збір сміття, перш ніж навіть запустити ядро?

C призначений для низького рівня, близького до апаратних завдань. Проблема? це така приємна мова, що її вдалий вибір і для багатьох завдань вищого рівня. Мовні чіти знають про ці способи використання, але вони повинні підтримувати вимоги драйверів пристроїв, вбудованого коду та операційних систем як пріоритетних.


2
C добре для високого рівня? Я пирхнула своїм напоєм по всій клавіатурі.
DeadMG

5
Що ж, він сказав "багато завдань вищого рівня". Він міг би рахувати тролів (один, два, багато ...). І він насправді не сказав вище за що. Жарти в сторону, хоча, це правда , - свідоцтво того , що багато значущі проекти більш високого рівня , які були успішно розроблені в C. Там може бути кращий вибір в даний час для багатьох з цих проектів, але робочий проект більш переконливі докази , ніж спекуляції про те , що може Був.
Steve314

Є кілька керованих операційних систем, і вони працюють досить добре. Насправді, коли ви робите всю систему керованою, показник продуктивності від використання керованого коду падає навіть нижче, аж до швидшого, ніж некерований код у реальних сценаріях. Звичайно, це все "дослідницькі ОС" - майже немає способу зробити їх сумісними з існуючим некерованим кодом, окрім створення повністю віртуалізованої некерованої ОС у керованій ОС. Microsoft в якийсь момент запропонував, що вони можуть замінити Windows Server одним із таких, оскільки все більше і більше кодів сервера пишеться на .NET.
Луань

6

Коротка і нудна відповідь на це запитання полягає в тому, що для людей, які пишуть смітники, там повинна бути мова, яка не збирається сміттям. Це концептуально не просто мати мову , який в той же час дозволяє дуже точний контроль над макетом пам'яті і має GC працює на вершині.

Інше питання - чому у C та C ++ немає сміттєзбірників. Ну, я знаю, що у C ++ є декілька з них, але вони не дуже популярні, оскільки вони змушені мати справу з мовою, яка в першу чергу не була розроблена як GC-ed, і люди, які все ще використовують C ++ у цей вік насправді не той вид, який пропускає GC.

Крім того, замість того, щоб додавати GC до старої мови, що не стосується GC, фактично простіше створити нову мову, яка має більшу частину того ж синтаксису, підтримуючи GC. Java та C # - хороші приклади цього.


1
Десь на programmers.se або ТАК, хтось висловив мені думку про те, що хтось працював над самозавантажуваним сміттям - IIRC в основному реалізував VM за допомогою мови GC, з підмножиною завантаження, що використовується для самої реалізації GC. Я забув ім'я. Коли я переглянув це, виявилося, що вони взагалі ніколи не досягали стрибка з підмножини без GC на робочий рівень GC. Це є в принципі можливо, але AFAIK воно ніколи не було досягнуто на практиці - це, звичайно, справа робити речі важкий шлях.
Steve314

@ Steve314: Я хотів би побачити це, якщо ти коли-небудь згадаєш, де ти його знайшов!
hugomg

знайшов це! Дивіться коментарі до stackoverflow.com/questions/3317329/… з посиланням на Klein VM. Частина проблеми з її пошуком - питання було закрите.
Steve314

BTW - Я не можу почати свої коментарі з @missingno - що дає?
Steve314

@ steve314: Отримавши відповідь до цієї теми, я вже отримую сповіщення про всі коментарі. Здійснення @ -посту в цьому випадку було б зайвим і заборонено SE (не запитуйте мене, чому ). (Однак справжньою причиною є те, що мій номер відсутній)
hugomg

5

Є різні питання, в тому числі ...

  • Хоча GC був винайдений до C ++, а можливо, і до C, і C, і C ++ були реалізовані до того, як GC були широко прийняті як практичні.
  • Ви не можете легко реалізувати мову та платформу GC без основної мови, яка не є GC.
  • Хоча GC демонструє ефективнішу ефективність, ніж не-GC, для типового коду додатків, розробленого в типових часових масштабах тощо, є проблеми, коли більше зусиль щодо розробки - це хороший компроміс, а спеціалізоване управління пам’яттю перевершить загальний цільовий ПК. Крім того, C ++, як правило, демонструється більш ефективно, ніж більшість мов GC, навіть без додаткових зусиль із розробки.
  • GC не є універсально безпечнішим за RAII у стилі C ++. RAII дозволяє автоматично очищати ресурси, крім пам’яті, в основному тому, що він підтримує надійні та своєчасні деструктори. Вони не можуть поєднуватися зі звичайними методами ГК через проблеми з еталонними циклами.
  • Мови GC мають свої характерні види витоків пам’яті, особливо це стосується пам’яті, яка більше ніколи не буде використовуватися, але там, де існували існуючі посилання, які ніколи не були скасовані чи перезаписані. Необхідність робити це явно не принципово відрізняється від потреби deleteабо freeявно. Підхід GC все ще має перевагу - немає звисаючих посилань - і статичний аналіз може зафіксувати деякі випадки, але знову ж таки, немає жодного ідеального рішення для всіх випадків.

По суті, частково йдеться про вік мов, але все одно завжди знайдеться місце для мов, що не належать до GC, - навіть якщо це трохи ніше місце. І якщо серйозно, то в C ++ відсутність GC не є великою справою - вашою пам’яттю керують інакше, але вона не керована.

C ++, що управляється мікрософт, має принаймні деяку здатність змішувати GC та non-GC в одному додатку, що дозволяє поєднувати переваги кожного з них, але я не маю досвіду сказати, наскільки добре це працює на практиці.

Посилання на повторні відбиття на відповідні відповіді моїх ...


4

Збір сміття принципово несумісний із системою мови, яка використовується для розробки драйверів для апаратних засобів, що підтримують DMA.

Цілком можливо, що єдиний вказівник на об'єкт зберігатиметься в апаратному регістрі в деякій периферії. Оскільки збирач сміття не знає про це, він вважає, що об’єкт недоступний, і збирати його.

Цей аргумент є подвійним для ущільнення GC. Навіть якщо ви обережно підтримували посилання в пам'яті на об'єкти, які використовуються апаратними периферійними пристроями, коли GC перемістив об'єкт, він не знатиме, як оновити покажчик, що міститься в периферійному реєстрі конфігурацій.

Отже, зараз вам знадобиться суміш нерухомих буферів DMA та керованих GC об'єктів, а це означає, що у вас є всі недоліки обох.


Можливо, всі недоліки обох, але менше примірників кожного недоліку, і однакові переваги. Зрозуміло, що існує складність у тому, щоб мати більше видів управління пам'яттю для вирішення, але також можна уникнути складності, вибравши правильного коня для кожного курсу у межах вашого коду. Навряд чи, я думаю, але там є теоретичний розрив. Раніше я міркував про змішування GC та non-GC однією і тією ж мовою, але не для драйверів пристроїв - більше для того, щоб мати в основному GC-додаток, але з деякими бібліотеками структури даних, керованими пам'яттю низького рівня.
Steve314

@ Steve314: Чи не скажете ви, що запам'ятовування, які об’єкти потрібно звільнити вручну, настільки ж важке, як і запам'ятовування, щоб звільнити все? (Звичайно, розумні покажчики можуть допомогти з будь-яким, тому жоден з них не є величезною проблемою) І вам потрібні різні пули для об'єктів, керованих вручну, проти зібраних / сумісних об'єктів, оскільки ущільнення не працює добре, коли фіксовані об'єкти розкидані по всьому. Так багато зайвої складності ні за що.
Бен Войгт

2
Не в тому випадку, якщо існує чіткий поділ між кодом високого рівня, який є всім GC, і кодом низького рівня, який відключається від GC. Я в основному розробляв цю ідею, дивлячись на D кілька років тому, що дозволяє відмовитися від GC, але не дозволяє повернутися назад. Візьмемо для прикладу бібліотеку дерев B +. Контейнер в цілому повинен бути GC, але вузли структури даних, мабуть, ні - це більш ефективно робити індивідуальне сканування через вузли листів, ніж змусити GC робити рекурсивний пошук через гілки вузлів. Однак для цього сканування потрібно повідомляти про вміщені елементи в GC.
Steve314

Справа в тому, що це вміщений фрагмент функціоналу. Трактування B + деревних вузлів як спеціального керування пам'яттю WRT не відрізняється від трактування їх як спеціальних WRT - B + деревних вузлів. Це інкапсульована бібліотека, і код програми не повинен знати, що поведінка GC була обведена / спеціалізована. За винятком того, що, принаймні в той час, це було неможливо в D - як я вже сказав, жодного способу не повернутись і повідомити про вміщені елементи до GC як потенційних коренів GC.
Steve314

3

Тому що C & C ++ - це порівняно низькі рівні мови, призначені для загальних цілей, навіть, наприклад, для роботи на 16-бітовому процесорі з 1 МБ пам'яті у вбудованій системі, який не міг дозволити собі витрачати пам'ять з gc.


1
"Вбудована система"? У той час, коли C був стандартизований (1989 р.), Йому потрібно було обробляти ПК з 1 Мб пам'яті.
dan04

Я згоден, я наводив більш сучасний приклад.
Петруза

1 Мб ??? Святий шмолей, кому коли-небудь знадобиться стільки оперативної пам'яті? </billGates>
Марк К

2

У C ++ та C. є сміттєзбірники. Не впевнені, як це працює в C, але в C ++ ви можете використовувати RTTI, щоб динамічно відкривати ваш об’єктний графік і використовувати його для збору сміття.

Наскільки мені відомо, ви не можете написати Java без сміттєзбірника. Невеликий пошук виявив це .

Ключова відмінність Java від C / C ++ полягає в тому, що у C / C ++ вибір завжди за вами, тоді як у Java ви часто залишаєтесь без варіантів за дизайном.


А також, що виділені сміттєзбірники краще впроваджуються, ефективніше і краще вписуються в мову. :)
Макс

Ні, ви не можете використовувати RTTI для динамічного виявлення об'єктного графіка в C / C ++: Це звичайні старі об'єкти даних, які все псують. Інформація про RTTI просто не зберігається в простому старому об'єкті даних, який би дозволяв сміттєзбірнику розмежовувати покажчики та не вказівники всередині цього об'єкта. Ще гірше, що вказівники не повинні бути ідеально вирівняні на всьому апаратному забезпеченні, тому, враховуючи 16-байтний об’єкт, є 9 можливих місць, в яких може бути збережений 64-бітний покажчик, лише два з яких не перетинаються.
cmaster

2

Це компроміс між продуктивністю та безпекою.

Немає гарантії, що ваш сміття буде зібрано на Java, тому він може довгий час зависати, використовуючи простір, тоді як сканування невизначених об'єктів (тобто сміття) також займає більше часу, ніж явне видалення або звільнення невикористаного об'єкта.

Перевагою є, звичайно, те, що можна створити мову без покажчиків або без витоку пам'яті, тому швидше створюється правильний код.

У цих дебатах іноді може бути невеликий "релігійний" край - будьте попереджені!


1

Ось перелік властивих проблем GC, які роблять його непридатним для використання в системній мові на зразок C:

  • GC повинен працювати нижче рівня коду, об'єктами якого він керує. Такого рівня в ядрі просто немає.

  • GC повинен час від часу зупиняти керований код. Тепер подумайте, що б сталося, якби це зробило ваше ядро. Вся обробка на вашій машині зупиниться, скажімо, на мілісекунду, тоді як GC сканує всі наявні розподіли пам'яті. Це знищило б усі спроби створити системи, які працюють під суворими вимогами реального часу.

  • GC повинен вміти розрізняти покажчики та не-покажчики. Тобто він повинен вміти переглядати кожен існуючий об’єкт пам'яті та вміти складати список зсувів, де можна знайти його вказівники.

    Це відкриття повинно бути ідеальним: GC повинен бути в змозі переслідувати всі покажчики, які він виявляє. Якщо вона відкине помилковий позитив, вона, швидше за все, вийде з ладу. Якщо не вдалося виявити помилковий негатив, воно, ймовірно, знищить об'єкт, який все ще використовується, зірвавши керований код або мовчки пошкодивши його дані.

    Це абсолютно вимагає, щоб інформація про тип зберігалася у кожному існуючому об'єкті. Однак і C, і C ++ дозволяють використовувати звичайні старі об'єкти даних, які не містять інформації про тип.

  • GC - це властива повільна справа. Програмісти, які були соціалізовані з Java, можуть не усвідомлювати цього, але програми можуть бути на порядок швидшими, коли вони не реалізовані на Java. І одним із факторів, які уповільнюють Java, є GC. Це те, що перешкоджає використанню мов GCed, як Java, у суперкомп'ютері. Якщо ваша машина коштує мільйон на рік споживання електроенергії, ви не хочете платити навіть 10% від цього за вивезення сміття.

C і C ++ - це мови, створені для підтримки всіх можливих випадків використання. І, як бачите, багато таких випадків використання виключаються зі збирання сміття. Отже, для підтримки цих випадків використання C / C ++ не можна збирати сміття.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.