Загрузка общих библиотек и Использование оперативной памяти

Нет никакого пути (что я знаю о) к непосредственно локальным переменным сценария доступа вне контекста того сценария; <SID> только работы для функций (и только в отображениях).

Вы могли обеспечить косвенный доступ через функцию, хотя:

function! s:FoobarHash()
  return s:Foobar
endfunction
function! s:MySurroundingFunctionIWantToKeep()
  let s:Foobar={'foo': 'bar'}
  map \42 :echo <sid>FoobarHash()['foo']<cr>
endfunction
call s:MySurroundingFunctionIWantToKeep()

В зависимости от того, как изолированный Вы хотите сохранить переменную, Вы могли сделать функцию “средства доступа” более строгой (только позволяют определенные ключи, только позволяют доступ для чтения, только позволяют записи определенным ключам, и т.д.).

let s:Foobar={'foo': 'bar', 'baz': 'quux'}
function! s:FoobarAccess(...)
  " Provide limited access to the script-local hash s:Foobar

  if a:0 == 1
    " allow read access to all keys
    return s:Foobar[a:1]

  elseif a:0 == 2
    " allow write access to only 'foo'
    if a:1 !=# 'foo'
      throw 'FoobarAccess: not allowed to write to key ' . a:1
    endif
    let old = s:Foobar[a:1]
    let s:Foobar[a:1] = a:2
    return old

  else
    throw 'FoobarAccess must take exactly one or two arguments'
  endif
endfunction


map \42 :echo <sid>FoobarAccess('foo')<cr>
map \43 :echo <sid>FoobarAccess('foo','new value')<cr>
map \44 :echo <sid>FoobarAccess('baz')<cr>
map \45 :echo <sid>FoobarAccess('baz',1)<cr>
41
24.03.2014, 14:25
1 ответ

ПРИМЕЧАНИЕ. Я предполагаю, что на вашем компьютере есть блок отображения памяти (MMU). Существует версия Linux (µClinux), для которой не требуется MMU, и этот ответ к ней неприменим.

Что такое MMU? Это аппаратное обеспечение - часть процессора и / или контроллера памяти. Понимание связывания разделяемых библиотек не требует от вас точного понимания того, как работает MMU, просто MMU позволяет иметь различие между логическими адресами памяти (теми, которые используются программами) и физическими адреса памяти (реально присутствующие на шине памяти). Память разбита на страницы, обычно размером 4K в Linux. Для страниц 4k логические адреса 0–4095 - это страница 0, логические адреса 4096–8191 - страница 1 и т. Д. MMU отображает их на физические страницы RAM, и каждая логическая страница обычно может быть сопоставлена ​​с 0 или 1 физическими страницами.Данная физическая страница может соответствовать нескольким логическим страницам (так распределяется память: несколько логических страниц соответствуют одной и той же физической странице). Обратите внимание, что это применимо независимо от ОС; это описание оборудования.

При переключении процесса ядро ​​изменяет отображение страниц MMU, так что каждый процесс имеет собственное пространство. Адрес 4096 в процессе 1000 может (и обычно так) полностью отличаться от адреса 4096 в процессе 1001.

Практически всякий раз, когда вы видите адрес, это логический адрес. Программы пользовательского пространства почти никогда не имеют дело с физическими адресами.

Теперь есть несколько способов создания библиотек. Допустим, программа вызывает функцию foo () в библиотеке. ЦП на самом деле ничего не знает о символах или вызовах функций - он просто знает, как перейти к логическому адресу и выполнить любой найденный там код. Есть несколько способов сделать это (и аналогичные вещи применимы, когда библиотека обращается к своим собственным глобальным данным и т. Д.):

  1. Он может жестко запрограммировать какой-то логический адрес для вызова. Это требует, чтобы библиотека всегда загружалась по одному и тому же логическому адресу. Если двум библиотекам требуется один и тот же адрес, динамическое связывание завершится ошибкой, и вы не сможете запустить программу. Для библиотек могут потребоваться другие библиотеки, поэтому в основном это требует, чтобы каждая библиотека в системе имела уникальные логические адреса. Но это очень быстро, если работает. (Вот как что-то делал a.out, и вроде как работает предварительная ссылка).
  2. Он мог жестко запрограммировать поддельный логический адрес и указать динамическому компоновщику отредактировать правильный адрес при загрузке библиотеки. При загрузке библиотек на это уходит немало времени, но после этого происходит очень быстро.
  3. Это могло бы добавить уровень косвенности: использовать регистр ЦП для хранения логического адреса, по которому загружена библиотека, а затем обращаться ко всему как к смещению от этого регистра. Это накладывает затраты на производительность при каждом доступе.

Практически никто больше не использует №1, по крайней мере, в системах общего назначения. Сохранение этого уникального логического списка адресов невозможно в 32-битных системах (их недостаточно), а в 64-битных системах это кошмар для администрирования. Однако предварительное связывание делает это для каждой системы.

Используется ли №2 или №3, зависит от того, была ли библиотека построена с опцией GCC -fPIC (независимый от позиции код). №2 без, №3 с. Обычно библиотеки создаются с помощью -fPIC , поэтому происходит №3.

Подробнее см. Ульрих Дреппер Как писать общие библиотеки (PDF) .

Итак, наконец, на ваш вопрос можно ответить:

  1. Если библиотека построена с помощью -fPIC (как это почти наверняка должно быть), то подавляющее большинство страниц точно соответствуют то же самое для каждого процесса, который его загружает. Ваши процессы a и b вполне могут загружать библиотеку по разным логическим адресам, но они будут указывать на одни и те же физические страницы: память будет совместно использоваться.Кроме того, данные в ОЗУ точно соответствуют тому, что находится на диске, поэтому они могут быть загружены только при необходимости обработчику ошибок страницы.
  2. Если библиотека построена без -fPIC , то оказывается, что большинство страниц библиотеки потребуют редактирования ссылок, и они будут другими. Следовательно, они должны быть отдельными физическими страницами (поскольку они содержат разные данные). Это означает, что они не разделяются. Страницы не соответствуют тому, что находится на диске,поэтому я не удивлюсь, если будет загружена вся библиотека. Конечно, впоследствии его можно выгрузить на диск (в файле подкачки).

Вы можете проверить это с помощью инструмента pmap или напрямую, проверив различные файлы в / proc . Например, вот (частичный) вывод pmap -x на двух разных вновь созданных bc s. Обратите внимание, что адреса, показанные pmap, как правило, являются логическими адресами:

pmap -x 14739
Address           Kbytes     RSS   Dirty Mode  Mapping
00007f81803ac000     244     176       0 r-x-- libreadline.so.6.2
00007f81803e9000    2048       0       0 ----- libreadline.so.6.2
00007f81805e9000       8       8       8 r---- libreadline.so.6.2
00007f81805eb000      24      24      24 rw--- libreadline.so.6.2


pmap -x 17739
Address           Kbytes     RSS   Dirty Mode  Mapping
00007f784dc77000     244     176       0 r-x-- libreadline.so.6.2
00007f784dcb4000    2048       0       0 ----- libreadline.so.6.2
00007f784deb4000       8       8       8 r---- libreadline.so.6.2
00007f784deb6000      24      24      24 rw--- libreadline.so.6.2

Вы можете видеть, что библиотека загружается несколькими частями, а pmap -x дает подробную информацию по каждой отдельно. Вы заметите, что логические адреса этих двух процессов различаются; разумно ожидать, что они будут одинаковыми (поскольку работает одна и та же программа, и компьютеры обычно предсказуемы), но есть функция безопасности, называемая рандомизацией разметки адресного пространства , которая намеренно рандомизирует их.

По разнице в размере (килобайтах) и резидентном размере (RSS) видно, что не был загружен весь сегмент библиотеки. Наконец, вы можете видеть, что для более крупных сопоставлений значение dirty равно 0, что означает, что оно точно соответствует тому, что находится на диске.

Вы можете повторно запустить pmap -XX , и он покажет вам - в зависимости от версии ядра, которую вы используете, поскольку вывод -XX зависит от версии ядра, - что первое сопоставление имеет a Shared_Clean из 176, что точно соответствует RSS . Совместно используемая память означает, что физические страницы используются совместно несколькими процессами, и, поскольку он соответствует RSS, это означает, что вся библиотека, находящаяся в памяти, является общей (см. Также см. Ниже для дальнейшего объяснения совместной и . private):

pmap -XX 17739
         Address Perm   Offset Device   Inode  Size  Rss Pss Shared_Clean Shared_Dirty Private_Clean Private_Dirty Referenced Anonymous AnonHugePages Swap KernelPageSize MMUPageSize Locked                   VmFlagsMapping
    7f784dc77000 r-xp 00000000  fd:00 1837043   244  176  19          176            0             0             0        176         0             0    0              4           4      0       rd ex mr mw me sd  libreadline.so.6.2
    7f784dcb4000 ---p 0003d000  fd:00 1837043  2048    0   0            0            0             0             0          0         0             0    0              4           4      0             mr mw me sd  libreadline.so.6.2
    7f784deb4000 r--p 0003d000  fd:00 1837043     8    8   8            0            0             0             8          8         8             0    0              4           4      0       rd mr mw me ac sd  libreadline.so.6.2
    7f784deb6000 rw-p 0003f000  fd:00 1837043    24   24  24            0            0             0            24         24        24             0    0              4           4      0    rd wr mr mw me ac sd  libreadline.so.6.2


См. также

54
27.01.2020, 19:35

Теги

Похожие вопросы