Какую стратегию следует использовать в долгосрочном приложении Common Lisp для управления мусором? - PullRequest
13 голосов
/ 13 апреля 2009

Если я размещаю долго работающее приложение, например веб-сервер, в образе Common Lisp, какую стратегию мне следует использовать для управления сборщиком мусора?

Я предполагаю, что по умолчанию сборщик мусора имеет право тратить много времени на сортировку кучи, порой я не могу предсказать. Это может повлиять на конкретный запрос браузера способами, которые я не хочу.

Есть ли в Common Lisp метод для управления этим? Может быть, побуждая его работать «мало-часто»?

Ответы [ 2 ]

25 голосов
/ 13 апреля 2009

Несколько реализаций Lisp имеют отличные сборщики мусора. Особая проблема заключается в том, что приложения на Лиспе часто имеют высокую скорость выделения небольших объектов (conses, ...).

Есть несколько вещей, которые следует учитывать.

  • Точный и консервативный ГХ. Я не большой поклонник консервативных группировок (Boehm и т. Д.) Для Lisp. Проблема консервативных сборщиков мусора заключается в том, что они не находят весь мусор. Это может стать проблемой для долго работающих программ и привести к фрагментации и неиспользованию неиспользуемой памяти. Точные GC используют информацию тега данных Lisp и могут идентифицировать каждый тип данных каждого объекта. Консервативные GC были изобретены для реализаций языка программирования, которые не используют теговые данные (C ++, ...).

  • копирование GC, сжатие GC. Для борьбы с фрагментацией памяти в долго выполняющихся Лиспах может быть полезен GC, который сжимает и локализует объекты. Иногда возникает проблема, когда нужно перефразировать хеш-таблицы (потому что местоположение меняется). Копирующему ГХ может потребоваться больше памяти (поскольку имеется пространство от и до памяти). Но когда ГХ копирует объекты из одного пространства памяти в другое, это автоматически делает его более компактным. Более продвинутые GC (как на Lisp Machine) также могут сортировать объекты и размещать объекты одного типа рядом друг с другом - при условии, что это ускорит доступ к объектам.

  • эфемерный GC. Это означает, что существует первый этап GC, который выполняется исключительно в основной памяти и получает некоторую поддержку от блока управления памятью для идентификации измененных областей памяти. Сканирование основной памяти происходит быстрее, чем сканирование виртуальной памяти, а сканирование только измененных областей памяти дополнительно сокращает объем работы. Когда большое количество объектов выделяется и быстро превращается в мусор, это дает очень короткие GC-паузы.

  • Поколение ГХ. Обычно ГК в настоящее время являются поколениями. Существует более одного поколения, и объекты, пережившие несколько ГХ, переводятся в старшее поколение. Обычно только первое поколение GCed очень часто.

  • Tuning. GC, скажем, LispWorks и Allegro CL имеют множество ручек настройки. Специально для долгосрочных приложений имеет смысл прочитать руководство и, например, настроить количество поколений, их размеры и другие вещи.

  • виртуальная память. GC над виртуальной памятью обычно очень медленный. Избегайте этого, если возможно - добавьте больше оперативной памяти на машины.

  • ручное управление памятью. Например, веб-сервер CL-HTTP выполняет некоторое ручное управление памятью, используя resources . Это пулы предварительно выделенных объектов, которые могут быть очень быстро переинициализированы. Машины Лисп использовали это много. Типичное использование их в буферах чтения для потоков. Вместо создания новых строк при каждой операции чтения полезно использовать многократно используемые буферы.

  • выделение стека. Некоторые Common Lisp допускают выделение стека для некоторых данных - выход из блока автоматически освобождает память. Это предполагает, что на память больше не ссылаются при выходе из блока. См. Декларацию dynamic-extent.

  • одновременный сборщик мусора. Ни одна из обычных реализаций Common Lisp не имеет одновременной поддержки GC AND для одновременных потоков Lisp. Некоторые реализации имеют параллельные потоки Lisp, но GC остановит их все, пока он работает. Если реализация Lisp работает на JVM, как ABCL, то она может использовать параллельный / параллельный GC JVM.

  • профилирование выделения памяти. Если вы не уверены, где происходит распределение и что делает GC, вы должны выяснить это, используя информацию профилирования.

Если ваш Lisp имеет точный GC поколения, который работает в основной памяти, трудно получить проблемы с длинными паузами. Например, Clozure CL (бесплатная реализация Common Lisp) имеет очень хорошую реализацию GC на некоторых платформах. Вы хотите избежать фрагментации памяти и сборок мусора в виртуальной памяти. При необходимости используйте 64-битную реализацию Lisp с большей оперативной памятью.

Указатели:

Из документации видно, что LispWorks и Allegro CL имеют множество ручек для настройки GC.

Common Lisp имеет несколько функций, связанных со средой реализации. (ROOM) - это функция, которая дает обзор использования памяти. (ROOM t) дает более подробную информацию (здесь LispWorks):

CL-USER 2 > (room t)
 Generation 0:  Total Size 1823K, Allocated 1090K, Free 725K 
          Segment 2008AAB8: Total Size 507K, Allocated 361K, Free 142K
                    minimum free space 64K, 
                      Awaiting promotion = 0K, sweeps before promotion =10
          Segment 217E7050: Total Size 1315K, Allocated 729K, Free 582K
                    minimum free space 0K, 
                      Awaiting promotion = 0K, sweeps before promotion =2
 Generation 1:  Total Size 1397K, Allocated 513K, Free 871K 
          Segment 20CB9A50: Total Size 68K, Allocated 48K, Free 15K
                    minimum free space 0K, 
                      Awaiting promotion = 0K, sweeps before promotion =4
          Segment 216D7050: Total Size 1088K, Allocated 331K, Free 752K
                    minimum free space 0K, 
                      Awaiting promotion = 0K, sweeps before promotion =4
          Segment 2004E4F8: Total Size 241K, Allocated 133K, Free 103K
                    minimum free space 0K, static
 Generation 2:  Total Size 2884K, Allocated 1290K, Free 1585K 
          Segment 21417050: Total Size 2816K, Allocated 1227K, Free 1584K
                    minimum free space 0K, 
                      Awaiting promotion = 0K, sweeps before promotion =4
          Segment 20DA5DA0: Total Size 68K, Allocated 62K, Free 1K
                    minimum free space 117K, 
                      Awaiting promotion = 0K, sweeps before promotion =4
 Generation 3:  Total Size 19373K, Allocated 19232K, Free 128K 
          Segment 20109A50: Total Size 11968K, Allocated 11963K, Free 0K
                    minimum free space 3K, 
                      Awaiting promotion = 0K, sweeps before promotion =10
          Segment 20DB6E18: Total Size 6528K, Allocated 6396K, Free 128K
                    minimum free space 0K, 
                      Awaiting promotion = 0K, sweeps before promotion =10
          Segment 20CCAAC8: Total Size 876K, Allocated 872K, Free 0K
                    minimum free space 0K, 
                      Awaiting promotion = 0K, sweeps before promotion =10

Total Size 25792K, Allocated 22127K, Free 3310K
2 голосов
/ 13 апреля 2009

Сборка мусора прошла долгий путь с первых дней, и была проделана большая работа, чтобы избежать непредсказуемого длительного ожидания. Я думаю, что для современных реализаций это уже в прошлом.

Однако детали сборки мусора могут различаться в зависимости от реализации. Существует не так много высококачественных реализаций Lisp, поэтому вам не составит труда обратиться к их документации по сбору мусора.

...