Кіріспе

Компьютерлік жадыны басқару әдістемесі

Компьютерлік ғылымда қолмен жадыны басқару – бағдарламашының пайдаланылмаған объектілерді немесе қоқысты анықтап, босату үшін қолмен берілген нұсқауларды пайдалануын білдіреді. 1990 жылдардың ортасына дейін өнеркәсіпте қолданылатын бағдарламалау тілдерінің көпшілігі қолмен жадыны басқаруды қолдады, бірақ қоқыс жинау 1959 жылдан бері, Lisp тілімен енгізілгеннен бастап бар еді. Дегенмен, қазіргі кезде Java сияқты қоқыс жинауды қолдайтын тілдер кеңінен танымал болып келеді, ал Objective C және Swift тілдері Автоматты сілтеме санау арқылы ұқсас мүмкіндіктерді ұсынады. Бүгінгі күні кеңінен қолданылатын негізгі қолмен басқарылатын тілдер – C және C++ тілдері. (C динамикалық жадының бөлінуіне қараңыз).

Сипаттама

Көптеген бағдарламалау тілдері бос жадтан жаңа нысанды қашан бөлу керектігін анықтау үшін қолмен техникаларды қолданады. C тілі malloc функциясын пайдаланады; C++ және Java тілдері new операторын пайдаланады; ал көптеген басқа тілдер (мысалы, Python) барлық нысандарды бос жадтан бөледі. Нысанды қашан жасау керектігін анықтау (нысан жасау) көбінесе оңай және қиындықсыз, бірақ нысан қоймасы сияқты техникалар нысанды дереу пайдаланудан бұрын жасауға мүмкіндік береді. Шын мәніндегі қиындық – нысанды жою, яғни нысанның енді қажет еместігін (қоқыс) анықтау және оның негізгі жадын қайта пайдалану үшін бос жадқа қайтаруды ұйымдастыру. Қолмен жадты бөлуде мұны бағдарламашы да қолмен анықтайды; C-де free, ал C++-де delete операторы сияқты функциялар арқылы. Бұл автоматты айнымалыларда сақталған нысандардың автоматты түрде жойылуымен қарама-қарсы, атап айтқанда (статикалық емес) функциялардың жергілікті айнымалылары, олар C және C++ тілдерінде өмір аяқталысымен жойылады.

Қолмен басқару және дұрыстығы

Жадты қолмен басқару дұрыс қолданылмаған жағдайда бағдарламаға бірнеше маңызды қателерді енгізеді, атап айтқанда жад қауіпсіздігін бұзу немесе жадтың ағуына себеп болады. Бұл қауіпсіздік бұзушылықтарының маңызды көзі болып табылады. Қолданылмаған нысан ешқашан бос жадтан босатылмаса, бұл жадтың ағуы деп аталады. Кейбір жағдайларда жадтың ағуы көтере алады, мысалы, өмірлік циклі бойына шектелген мөлшерде жадты "ағу" жасайтын бағдарлама немесе операциялық жүйеге сеніп, тоқтағанда ресурстарын босататын қысқа мерзімді бағдарлама. Дегенмен, көбінесе жадтың ағуы ұзақ уақыт бойы жұмыс істейтін бағдарламаларда кездеседі, және мұндай жағдайларда шексіз мөлшерде жад ағуы мүмкін. Мұндай жағдайда қол жетімді бос жад көлемі уақыт өте келе азаяды; ол толығымен толғанда бағдарлама құлайды. Объектінің жады бірнеше рет жойылса; объект бірнеше рет жойылса; егер бос жадта бөлінбеген объектіні басқару үшін көрсеткіш қолданылса, бағдарламашы осы көрсеткіштің нысанының жадын босатуға тырысса; немесе белгілі бір сыртқы тапсырма, жіп немесе процесс басқаратын жадтың кездейсоқ бөлігі арқылы объектіні басқару кезінде бағдарламашы объектінің күйін бұзса, мүмкін оның шегінен тыс жазып, жадты басқару деректерін зақымдаса, динамикалық жадты басқару жүйесінің күрт сәтсіздігіне әкелуі мүмкін. Мұндай әрекеттердің салдары үйіндінің бұзылуына, жаңадан құрылған, бірақ бірнеше рет жойылған объектінің орнында тұрған басқа объектінің мерзімінен бұрын жойылуына, жадты қорғау ережесін бұзудан туындаған сегментация қатесіне және басқа да белгісіз мінез-құлық түрлеріне алып келуі мүмкін. Жойылған нысандарға сілтемелер жойылғаннан кейін қолданылса, "жабайы көрсеткіштерге" айналады; мұндай көрсеткіштерді қолдануға тырысу қателерді анықтауды қиындатады. Тек қоқыс жинауды қолданатын тілдер мұндай екі түрлі қатеден сақтануға мүмкіндік береді. Жадтың ағуы орын алуы мүмкін (және шектелген ағу жиі ұрпақтық немесе консервативті қоқыс жинаумен кездеседі), бірақ әдетте қолмен басқару жүйелеріндегі жадтың ағуына қарағанда аз зиянды болады.

Ресурстарды алу - инициализациялау

Қолмен жадты басқарудың бір артықшылығы бар, ол автоматты ресурстарды басқаруға мүмкіндік береді, «Ресурсты алу – инициализациялау» (RAII) парадигмасы арқылы. Бұл, егер объектілерде сирек кездесетін жүйелік ресурстар (мысалы, графикалық ресурстар, файл дескрипторлары немесе деректер базасы қосылымдары) болса, олар объекті жойылған кезде босатылуы тиіс болғанда пайда болады – яғни, ресурс иелігінің мерзімі объектінің мерзімімен байланысты болуы керек. Қолмен басқаруды қолдайтын тілдер мұны объектіні инициализациялау кезінде (конструкторда) ресурсты алу және объектіні жою кезінде (деструкторда) босату арқылы іске асыра алады, бұл нақты уақытта орындалады. Бұл «Ресурсты алу – инициализациялау» деп аталады. Бұл детерминистік сілтеме санауымен де қолданылуы мүмкін. C++ тілінде бұл мүмкіндік жадты босатуды автоматтандыру үшін одан әрі қолданылады, тілдің стандартты кітапханасындағы `shared_ptr` шаблонын қолдану арқылы жадты басқаруды жүзеге асыру – бұл кең таралған тәсіл. Дегенмен, `shared_ptr` барлық объектілерді пайдалану жағдайларына қолайлы емес. Бұл тәсіл көптеген қоқыс жиналатын тілдерде қолданылмайды – әсіресе іздеуге негіделген қоқыс жинағыштарда немесе жетілдірілген сілтеме санауында, себебі түпкілікті әдіс детерминистік емес, және кейде осы әдіс мүлдем орындалмайды. Яғни, түпкілікті әдісті қашан және қалай шақыруға болатынын анықтау қиын; бұл көбінесе «түпкілікті әдіс мәселесі» деп аталады. Java және басқа GC тілдері жадтан басқа сирек кездесетін жүйелік ресурстарды басқару үшін жиі қолмен басқаруды қолданады: ресурстарды басқаратын кез келген объектінің `dispose` әдісін іске асыруы күтіледі, ол осы ресурстарды босатады және объектіні белсенді емес деп белгілейді. Бағдарламашылар графикалық ресурстардың «жоғалуын» болдырмау үшін қажет болған жағдайда `dispose` әдісін қолмен шақыруы керек. Графикалық ресурстарды босату үшін `finalize` әдісіне (Java-да түпкілікті әдістерді қалай іске асырады) сүйену Java бағдарламашылары арасында жаман практика ретінде қарастырылады, сондай-ақ Python-дағы `del` әдісіне де ресурстарды босату үшін сенуге болмайды. Стек ресурстары үшін (бір код блогында алынып, босатылатын ресурстар) бұл Python-дағы `with`, C#-тағы `using` немесе Java-дағы `try-with-resources` сияқты әртүрлі тіл құрылымдарымен автоматтандырылуы мүмкін.