如果需要背景,请参见here。简而言之,问题是:“bracket (mallocBytes n) free allocaBytes 与ojit_a之间的实际区别是什么?”

通常在C语言中,Foreign.Marshall.Alloc在堆栈上分配,而alloca在堆上分配。我不确定在Haskell中发生了什么,但是除了速度以外,我不希望上述方程之间有差异。但是,如果您单击背景链接,您就会知道,使用编译后的代码malloc会导致“双重释放或损坏”,而bracket (mallocBytes n) free可以正常工作(在GHCi中根本看不到问题,在两种情况下都可以正常工作)。

到目前为止,我已经花了两天时间进行痛苦的调试,并且我非常确信allocaBytes在某种程度上是不稳定的,其余代码是可靠的。我想找出bracket (mallocBytes n) free有什么问题。

最佳答案

bracket (mallocBytes size) free将使用C的mallocfree,而allocaBytes size将使用由GHC垃圾回收管理的内存。这本身已经是一个巨大的差异,因为PtrallocaBytes可能被未使用(但已分配)的内存包围着:

import Control.Exception
import Control.Monad (forM_)
import Foreign.Marshal.Alloc
import Foreign.Ptr
import Foreign.Storable

-- Write a value at an invalid pointer location
hammer :: Ptr Int -> IO ()
hammer ptr = pokeElemOff ptr (-1) 0 >> putStrLn "hammered"

main :: IO ()
main = do
  putStrLn "Hammer time! Alloca!"
  forM_ [1..10] $ \n ->
    print n >> allocaBytes 10 hammer

  putStrLn "Hammer time! Bracket"
  forM_ [1..10] $ \n ->
    print n >> bracket (mallocBytes 10) free hammer

结果:
Hammer time! Alloca!
1
hammered
2
hammered
3
hammered
4
hammered
5
hammered
6
hammered
7
hammered
8
hammered
9
hammered
10
hammered
Hammer time! Bracket
1
hammered
<program crashes>

如您所见,尽管我们使用了arr[-1] = 0,但allocaBytes高兴地忽略了该错误。但是,如果您写位置free-1(通常)会在您的脸上炸毁。如果另一个分配的内存区域出现内存损坏,它也会在您的脸上炸毁*。

另外,对于allocaBytes,指针很可能指向已分配的内存中的某个位置,而不是指向某个内存的开头,例如
nursery = malloc(NURSERY_SIZE);

// ...

pointer_for_user = nursery + 180;

// pointer_for_user[-1] = 0 is not as
// much as a problem, since it doesn't yield undefined behaviour

这意味着什么?好吧,allocaBytes不太可能在您的脸上炸毁,但是代价是您没有注意到C代码变体是否会导致内存损坏。更糟糕的是,一旦您在allocaBytes返回的范围之外书写,您可能会无声地破坏其他Haskell值。

但是,我们在这里谈论的是不确定的行为。上面的代码可能会或可能不会在您的系统上崩溃。它也可能在allocaBytes部分崩溃。

如果我是你,我会trace the malloc and free calls

*我曾经在程序中间出现“双重使用免费”错误。调试了所有内容,重写了大多数“不良”例程。不幸的是,该错误在调试版本中消失了,但在发行版本中再次出现。原来,在main的前十行中,我不小心将b[i - 1]写入了i = 0

关于haskell - "bracket (mallocBytes n) free"和 "allocaBytes"有什么区别?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/41410805/

10-10 13:16