1

Тема: smart pointers, memory leaks та garbage collection загалом

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

В мовах в яких є GC, чи працюючи в с++ з розумними вказівниками меморі лік отримати можна тільки через проблему циклічних посилань(чи є ще якісь?), коли маємо шось типу

p1 = p2
p2 = p1

але що це спричиняє?
кажуть що це трапляється через те, що лічильник кожного вказівника не зможе зменшитись (стати < 2) і відповідно GC не зможе почистити ту пам'ять на яку вони вказують, бо на неї вічно існуватимуть посилання

але чому? хіба при виході з такого скоупу ці вказівники не почнуть знищуватись (р2, р1) тим самим декрементуючи свій лічильник і в кінцевому результаті не очистять пам'ять?

{
   p1 = p2
   p2 = p1
}  

чи я якось неправильно зрозумів проблему?

ну і я чув що ця проблема вирішується певним чином weak_ptr'ами, бо їхнє посилнання не є значущим, тобто через них лічильник не збільшуватиметься

та і взагалі в с++ смартпоінтери ж можна вважати як певного роду реалізацію збирача сміття, чи не так?
можливо я тут взагалі напутав праведне з грішним(думаю шо десь точно та :)
тож допоможіть мені систематизувати весь цей сумбур)

2

Re: smart pointers, memory leaks та garbage collection загалом

Ви неправильно представили ситуацію:

class B;
class A {
  public:  B *pb;
};
class B {
  public:  A *pa;
};
...
A *a = new A; //припустимо, 0x0a00
a->pb = new B; //припустимо, 0x0b00
a->pb->pa = a;//циклічне посилання

А тепер губимо a:

a = NULL;

Якби був "примітивний" GC, він би побачив, що на 0x0a00 все ще посилаються (а саме, об'єкт 0x0b00) і не видалив би 0x0a00.
Розумні вказівники це все нормально розрулюють (в т.ч. за допомогою weak_ptr). І так, це певний аналог GC, але тут чітко контролюється момент запуску збирання.

Подякували: sensei, Chemist-i, Arete, Torbins, leofun015

3

Re: smart pointers, memory leaks та garbage collection загалом

Koala, дуже дякую, нарешті все стало на свої місця)

4 Востаннє редагувалося Torbins (06.05.2016 13:05:29)

Re: smart pointers, memory leaks та garbage collection загалом

Думаю, сьогодні можна виділити три основні підходи до роботи з пам'яттю:

  • Ручне керування пам'яттю. Тобто після кожного new обов'язково треба робити delete. Цей підхід використовують там, де треба мати хорошу швидкодію. Наприклад так пишуть рушії баз даних та 3D іграшок (ядро Unity в тому числі).

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

  • Лічильник посилань (ARC). Займає проміжну позицію між GC та ручним керуванням. Як і GC не є "безкоштовним", але на відміну від збирача сміття, робота лічильника посилань є повністю передбачуваною. При правильному застосуванні, програмувати з ARC не набагато складніше ніж з GC.

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

Загалом тенденція така, що чим складніші механізми роботи з пам'яттю, тим простіше писати код, і тим складніше потім шукати свої помилки.

Подякували: koala, Arete, leofun01, sensei4

5

Re: smart pointers, memory leaks та garbage collection загалом

Чудово розбірали, тільки пропустили RAII - це щось проміжне між ручним керуванням (власне, це і є впорядкування ручного) і ARC (не такий гнучкий).

6 Востаннє редагувалося -=ЮрА=- (08.05.2016 20:42:52)

Re: smart pointers, memory leaks та garbage collection загалом

sensei річ за меморі лік та короблення кучі йде для наступного випадку

#include <iomanip>
#include <iostream>
using namespace std;

template< class T >
class cPtr{
    T * ptr;
public:
    cPtr(T *p = 0){
        ptr = p;
    }
    T * operator()(void) const{
        return ptr;
    }
    ~cPtr(){
        delete ptr;
    }
};

int main(){
    int * val1 = new int[1];
    int * val2 = new int[1];
    (*val1) = 256;
    (*val2) = 128;
    cPtr< int > p1(val1);
    cPtr< int > p2(val2);
    cout<<hex<<p1()<<endl;
    cout<<hex<<p2()<<endl;
    p1 = p2;
    p2 = p1;
    cout<<hex<<p1()<<endl;
    cout<<hex<<p2()<<endl;
    return 0;
}

http://codepad.org/kTv0QrIM

0x8085438
0x8085460
0x8085460
0x8085460
block freed twice

Тобто якщо класс поінтера не має перевантаженого оператора копіювання, то будемо матри трабли.

вважати як певного роду реалізацію збирача сміття, чи не так?

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

Подякували: sensei1

7 Востаннє редагувалося -=ЮрА=- (08.05.2016 20:51:51)

Re: smart pointers, memory leaks та garbage collection загалом

Прихований текст

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

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