Как освободить память определенной структуры данных в Haskell?

Допустим, у меня есть несколько очень больших векторов. Они хранятся на диске. Мне нужно получить к ним доступ по отдельности, читая из каждого соответствующего файла, который поместит их в память. Я бы выполнил некоторую функцию на одном векторе, а затем перешел бы к следующему, к которому мне нужен доступ. Мне нужно иметь возможность указать каждому вектору в памяти собирать мусор каждый раз, когда мне нужно получить доступ к другому вектору. Я не уверен, что performMajorGC гарантирует, что вектор будет удален сборщиком мусора, если в моей программе указано, что я должен снова получить доступ к тому же вектору позже, ссылаясь на то же имя функции, которое считывает вектор с диска. В таком случае я бы снова прочитал его в память, использовал его, а затем собирал мусор. Как я могу убедиться, что это гаражная коллекция, используя то же имя функции для вектора, который читается из того же файла?

Буду признателен за любой совет спасибо

В ответ Даниэлю Вагнеру:

    myvec x :: Int -> IO (Vector (Vector ByteString))
    myvec x = do let ioy = do y <- Data.ByteString.Lazy.readFile ("data.csv" ++ (show x))
                              guard (isRight (Data.Csv.decode NoHeader y)) 
                              return y
                 yy <- ioy 
                 return (head $ snd $ partitionEithers [Data.Csv.decode NoHeader yy])

    myvecvec :: Vector (IO (Vector (Vector ByteString)))
    myvecvec = generate 100 (\x -> myvec x)

    somefunc1 :: IO (Vector (Vector ByteString)) -> IO ()
    somefunc1 iovv = do vv <- iovv
                        somefunc1x1 vv :: Vector (Vector ByteString) -> IO ()  

-- то же самое для somefunc2 и 3

    oponvec :: IO ()
    oponvec = do somefunc1 (myvecvec ! 0)
                 performGC
                 somefunc2 (myvecvec ! 1)
                 performGC
                 somefunc3 (myvecvec ! 0)
    

Предположительно, чтение в память — это IO действие. Ссылка на действие IO не содержит ссылку на результат, полученный этим действием. Так что почти наверняка performMajorGC достаточно. Но чтобы быть действительно уверенным, нам нужно увидеть код.

Daniel Wagner 22.03.2022 18:00

@DanielWagner Итак, будет ли код, который я написал в своем редактировании, эффективно приводить к сборке мусора каждого вектора, как я предполагал, между операциями? Мне даже нужно использовать PerformGC? Могу ли я полагаться на сборщик мусора для сбора каждого вектора, как я описал, без явного использования PerformGC?

Anon 22.03.2022 19:11

...да, ничего существенного не сохраняется от одной строки oponvec к другой. Но ничего себе, этот код можно значительно улучшить. Почему ioy заслуживает названия (в отличие от myvec x = do { y <- readFile ("data.csv" ++ show x); case decode NoHeader y of { Left err -> die (show err); Right v -> return v }}? Почему вообще существуют myvecvec и somefunc1 (в отличие от oponvec = do { myvec 0 >>= somefunc1x1; myvec 1 >>= somefunc1x1; myvec 0 >>= somefunc1x1 })?

Daniel Wagner 22.03.2022 19:23

@DanielWagner Извините, это было очень небрежно с моей стороны

Anon 22.03.2022 19:27
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
4
84
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Вы можете проверить это, используя слабый указатель следующим образом:

import qualified Data.Vector.Unboxed as V
import System.Mem.Weak
import System.Mem

main :: IO ()
main = do
  let xs = V.fromList [1..1000000:: Int]
  wkp <- mkWeakPtr xs Nothing
  performGC
  xs' <- deRefWeak wkp
  print xs'

В моей системе это печатает Nothing, что означает, что вектор был освобожден. Однако я не знаю, гарантирует ли GHC, что это произойдет.

Вот программа, которая проверяет предложение @amalloy:

import qualified Data.Vector.Unboxed as V
import Control.Monad
import Data.Word

{-# NOINLINE newLarge #-}
newLarge :: Word8 -> V.Vector Word8
newLarge n = V.replicate 5000000000 n -- 5GB

main :: IO ()
main = forM_ [1..10] $ \i -> print (V.sum (newLarge i))

Это использует ровно 5 ГБ на моей машине, что показывает, что никогда не бывает двух больших векторов, выделенных одновременно.

I need to be able to instruct each vector in memory to be garbage collected every time I need to access a different vector.

Ты? Почему? Если это просто потому, что они большие, и вы беспокоитесь о том, чтобы разместить вектор в памяти, то не беспокойтесь об этом. Если требуется место в памяти, а объект недоступен, сборщик мусора подберет его. Если память не нужна, ничего делать не нужно. И если объект достижим, запуск GC не поможет. Так что нет случаев, когда ручное вмешательство в сборщик мусора принесет пользу.

И если вы хотите собрать его по какой-либо другой причине, кроме освобождения памяти, вам нужно объяснить это в вопросе, потому что эта цель наверняка повлияет на ответы.

Пожалуйста, смотрите мой комментарий Даниэлю Вагнеру и мою правку в ответ на его вопрос. Я использую раздел подкачки очень часто, поэтому отключение подкачки для программ, которые превышают мою память, чтобы заставить GC собирать без использования подкачки, на самом деле не является для меня вариантом, насколько я смог это сделать. Параметр RTS -M(<size>) не работает для предотвращения доступа к подкачке.

Anon 22.03.2022 19:15

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

leftaroundabout 22.03.2022 19:22

Другие вопросы по теме