gpt4 book ai didi

haskell - 在 `unsafeDupablePerformIO` 内分配内存是否安全?

转载 作者:行者123 更新时间:2023-12-04 15:15:26 27 4
gpt4 key购买 nike

假设我有一个外部函数:

-- | Turns char* of the given size into a char* of size 16.
doSomethingFfi :: Ptr CUChar -> Ptr CUChar -> CSize -> IO ()
doSomethingFfi = undefined

函数是纯函数,所以我想在 Haskell 中将其表示为纯函数:

doSomething :: ByteArray bytes => bytes -> bytes
doSomething bs = unsafePerformIO $
alloc 16 $ \outPtr ->
withByteArray bs $ \inPtr ->
doSomethingFfi outPtr inPtr (fromIntegral $ length bs)

(这里我使用的是内存中的alloc。)

我的理解是,unsafePerformIOunsafeDupablePerformIO 之间的唯一区别是后者中的 IO 操作可以在不进行任何清理的情况下静默终止。

在我上面的例子中,基本上有两个 IO 操作发生了:1. 内存分配; 2.外呼。我不关心 2,因为它是纯的,但是我担心内存。

如果计算被静默中断,是否可以保证以这种方式分配的内存不会泄漏?如果外部函数还需要我必须分配/清理的临时存储,我会使用 alloca为此,使用 unsafeDupablePerformIO 是否仍然安全?

最佳答案

大部分如我在评论中解释的那样,但不完全是:

分配

由于 alloca 目前已经实现,这是安全的。 alloca 是通过调用 allocaBytesAligned 实现的,其定义如下:

allocaBytesAligned :: Int -> Int -> (Ptr a -> IO b) -> IO b
allocaBytesAligned (I# size) (I# align) action = IO $ \ s0 ->
case newAlignedPinnedByteArray# size align s0 of { (# s1, mbarr# #) ->
case unsafeFreezeByteArray# mbarr# s1 of { (# s2, barr# #) ->
let addr = Ptr (byteArrayContents# barr#) in
case action addr of { IO action' ->
case action' s2 of { (# s3, r #) ->
case touch# barr# s3 of { s4 ->
(# s4, r #)
}}}}}

这会在垃圾收集堆中分配固定内存。如果您的操作提前中止,那么垃圾收集器迟早会回收它分配的内存。

分配

这不是必然安全的,但实际上可能是安全的。 alloc 是使用类方法 allocRet 定义的,不同的类型可以实现不同的方法。

与我在评论中的猜测相反,memory 中定义的实例看起来都很好——它们也分配固定内存。但是类没有将此记录为要求,原则上有人可以使用 Foreign.Marshall.Alloc.malloc 分配内存,在这种情况下,垃圾收集器不会自动处理内存。如果计算提前中止,这种假设的实现将无法确保释放内存。

关于haskell - 在 `unsafeDupablePerformIO` 内分配内存是否安全?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64396265/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com