У чому різниця між LocalAlloc і GlobalAlloc

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

У чому різниця між LocalAlloc та GlobalAlloc?

Важливий момент: ближні покажчики завжди відносні до селектора, зазвичай: до селектора даних.

Функція GlobalAlloc виділяє селектор, який може бути використаний для доступу до вашої кількості пам'яті (а якщо ви попросите виділити вам більше 64 Кб пам'яті, то відбудеться щось хвилююче, що, втім, зараз не важливо). Ви можете отримати доступ до пам'яті цього селектора через "далекий покажчик" ("far pointer"). "Далекий покажчик" - це селектор, з'єднаний з ближнім покажчиком (не забувайте: ближній покажчик відносний до селектора; коли ви з'єднуєте ближній покажчик з відповідним йому селектором, ви отримуєте далекий покажчик).

Кожен екземпляр (instance) програми та DLL має свій власний селектор даних, відомий як HINSTANCE, який я описував раніше. Селектор даних за промовчанням для коду в програмі був HINSTANCE цього екземпляра програми; селектор даних за замовчуванням для DLL був HINSTANCE цієї DLL. Тому, якщо у вас був ближній покажчик p, то розіменовуючи його як p^ із коду програми, ви отримували доступ до пам'яті щодо HINSTANCE екземпляра програми. Якщо ви розіменовували його в DLL, то ви отримували пам'ять щодо HINSTANCE вашої DLL.

Пам'ять, на яку посилається селектор за замовчуванням, може бути перетворена на "локальну купу" ("local heap") викликом функції LocalInit. Ініціалізація локальної купи зазвичай була однією з перших речей, які робила програма або DLL під час запуску (для DLL це було зазвичайєдиноюріччю, яку вона робила при завантаженні!). Коли у вас є локальнакупа, можна викликати LocalAlloc виділення з неї пам'яті. Функція LocalAlloc повертала ближній покажчик, що стосується селектора за замовчуванням, так що якщо ви викликали її з програмного модуля, вона виділяла пам'ять для HINSTANCE програми; якщо ви викликали її з DLL, вона виділяла пам'ять із HINSTANCE DLL.

Якщо ви були кмітливі, ви могли зрозуміти, що можна використовувати LocalAlloc для виділення пам'яті з інших блоків, не тільки з HINSTANCE. Все, що вам потрібно було для цього зробити, так це змінити ваш селектор за промовчанням на селектор для пам'яті, виділеної через GlobalAlloc, викликати функцію LocalAlloc, а потім відновити селектор за промовчанням. Це давало вам ближній покажчик, що стосується чогось, відмінного від селектора за замовчуванням, що було дуже страшною річчю. Але якщо ви були розумні і акуратно все робили, ви могли уникнути неприємностей.

Зауважте, що в 16-ти бітових Windows функції LocalAlloc і GlobalAlloc були зовсім різними! LocalAlloc повертала ближній покажчик, тоді як GlobalAlloc взагалі повертала селектор.

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

Ця історична різниця між локальною та глобальною пам'яттю досі залишається у Win32. Якщо у вас є функція, яка прийшла з 16 бітних Windows, і вонапередає право на пам'ять, вона працюватиме зі значеннями типу HGLOBAL. Класичним прикладом таких функцій є функції буфера обміну (clipboard). Якщо ви розміщуєте блок пам'яті в буфері обміну, він повинен бути виділений через HGLOBAL, тому що ви передаєте пам'ять буферу обміну, і він викличе GlobalFree, коли ця пам'ять стане йому не потрібна. Пам'ять, що передається через STGMEDIUM, набуває форми HGLOBAL з тієї ж причини.

Навіть у Win32, вам потрібно бути обережними і не переплутати локальну купу та глобальну. Пам'ять, виділена в одній, не може бути звільнена в іншій. Хоча функціональні відмінності переважно зникли; і семантика на цей момент практично ідентична. Усі дивацтво по ближнім і далеким покажчикам теж зникли при переході до Win32. Але функції локальної та глобальної куп, проте, залишаються двома різними і не пов'язаними інтерфейсами куп.

Я збираюся витратити кілька записів на опис можливостей 16 бітного менеджера пам'яті. Хоча сьогодні вам не потрібно знати їх, маючи перед собою історію, ви можете зрозуміти деякі підводні камені менеджера пам'яті Win32. Сьогодні ми вже трохи побачили це, коли логіка 16-бітного менеджера пам'яті встановила правила для буфера обміну.