Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell Lazy ByteString:某些情况下内存爆炸_Haskell_Lazy Evaluation - Fatal编程技术网

Haskell Lazy ByteString:某些情况下内存爆炸

Haskell Lazy ByteString:某些情况下内存爆炸,haskell,lazy-evaluation,Haskell,Lazy Evaluation,下面我们有两个看起来功能相当的程序。对于第一种情况,内存保持不变,而对于第二种情况,内存爆炸(在Ubuntu 14.04 64位中使用ghc 7.8.2和bytestring-0.10.4.0): 非爆炸性: --NoExplode.hs --ghc -O3 NoExplode.hs module Main where import Data.ByteString.Lazy as BL import Data.ByteString.Lazy.Char8 as BLC num = 1000000

下面我们有两个看起来功能相当的程序。对于第一种情况,内存保持不变,而对于第二种情况,内存爆炸(在Ubuntu 14.04 64位中使用ghc 7.8.2和bytestring-0.10.4.0):

非爆炸性:

--NoExplode.hs
--ghc -O3 NoExplode.hs
module Main where
import Data.ByteString.Lazy as BL
import Data.ByteString.Lazy.Char8 as BLC

num = 1000000000
bytenull = BLC.pack ""

countDataPoint arg sum
  | arg == bytenull = sum
  | otherwise = countDataPoint (BL.tail arg) (sum+1)

test1 = BL.last $ BL.take num $ BLC.cycle $ BLC.pack "abc" 
test2 = countDataPoint (BL.take num $ BLC.cycle $ BLC.pack "abc") 0

main = do
  print test1
  print test2
--Explode.hs
--ghc -O3 Explode.hs
module Main where
import Data.ByteString.Lazy as BL
import Data.ByteString.Lazy.Char8 as BLC

num = 1000000000
bytenull = BLC.pack ""

countDataPoint arg sum
  | arg == bytenull = sum
  | otherwise = countDataPoint (BL.tail arg) (sum+1)

longByteStr = BL.take num $ BLC.cycle $ BLC.pack "abc" 

test1 = BL.last $ longByteStr
test2 = countDataPoint (BL.take num $ BLC.cycle $ BLC.pack "abc") 0

main = do
  print test1
  print test2
爆炸:

--NoExplode.hs
--ghc -O3 NoExplode.hs
module Main where
import Data.ByteString.Lazy as BL
import Data.ByteString.Lazy.Char8 as BLC

num = 1000000000
bytenull = BLC.pack ""

countDataPoint arg sum
  | arg == bytenull = sum
  | otherwise = countDataPoint (BL.tail arg) (sum+1)

test1 = BL.last $ BL.take num $ BLC.cycle $ BLC.pack "abc" 
test2 = countDataPoint (BL.take num $ BLC.cycle $ BLC.pack "abc") 0

main = do
  print test1
  print test2
--Explode.hs
--ghc -O3 Explode.hs
module Main where
import Data.ByteString.Lazy as BL
import Data.ByteString.Lazy.Char8 as BLC

num = 1000000000
bytenull = BLC.pack ""

countDataPoint arg sum
  | arg == bytenull = sum
  | otherwise = countDataPoint (BL.tail arg) (sum+1)

longByteStr = BL.take num $ BLC.cycle $ BLC.pack "abc" 

test1 = BL.last $ longByteStr
test2 = countDataPoint (BL.take num $ BLC.cycle $ BLC.pack "abc") 0

main = do
  print test1
  print test2
其他详细信息:

--NoExplode.hs
--ghc -O3 NoExplode.hs
module Main where
import Data.ByteString.Lazy as BL
import Data.ByteString.Lazy.Char8 as BLC

num = 1000000000
bytenull = BLC.pack ""

countDataPoint arg sum
  | arg == bytenull = sum
  | otherwise = countDataPoint (BL.tail arg) (sum+1)

test1 = BL.last $ BL.take num $ BLC.cycle $ BLC.pack "abc" 
test2 = countDataPoint (BL.take num $ BLC.cycle $ BLC.pack "abc") 0

main = do
  print test1
  print test2
--Explode.hs
--ghc -O3 Explode.hs
module Main where
import Data.ByteString.Lazy as BL
import Data.ByteString.Lazy.Char8 as BLC

num = 1000000000
bytenull = BLC.pack ""

countDataPoint arg sum
  | arg == bytenull = sum
  | otherwise = countDataPoint (BL.tail arg) (sum+1)

longByteStr = BL.take num $ BLC.cycle $ BLC.pack "abc" 

test1 = BL.last $ longByteStr
test2 = countDataPoint (BL.take num $ BLC.cycle $ BLC.pack "abc") 0

main = do
  print test1
  print test2
区别在于,在
Explode.hs
中,我从
test1
的定义中提取了
BL.take num$BLC.cycle$BLC.pack“abc”
,并将其分配给自己的值
longByteStr

奇怪的是,如果我们在
Explode.hs
中注释掉
print test1
print test2
(但显然不是两者都注释掉),那么程序就不会爆炸


内存在
Explode.hs
中爆炸而不是在
NoExplode.hs
中爆炸是否有原因,以及为什么爆炸程序(
Explode.hs
)同时需要
print test1
print test2
才能爆炸?
/p>为什么
ghc
在一种情况下执行公共表达式消除,但不是在另一个?谁知道呢。可能是被内联杀死的常见表达式。基本上,这取决于内部实施

关于
-ddump simp
,请参见此SO问题:


我用
ghc-7.8.2
复制了它。它执行公共表达式消除。您可以检查
-ddump siml
的输出。所以你实际上创建了一个懒惰的bytestring


在第一个版本中,您创建了两个lazy bytestring<代码>打印测试1强制执行第一个测试,但它是动态垃圾收集的,因为没有其他人使用它。与打印test2相同,它强制第二个bytestring,并动态地执行GC'ed


在第二个版本中,您创建了一个lazybytestring<代码>打印测试1强制它,但它不能被GC'ed,因为它是
打印测试2
所需要的。因此,在第一次
打印后
将整个bytestring加载到内存中

如果删除一个
打印
,则bytestring将再次被动态GC'ed。因为它不在其他任何地方使用


PS.“GC'ed on fly”的意思是:
print
获取第一个块并将其输出到
stdout
。该区块可用于GC。然后,
prints
获取第二个块,等等。

“在第二个版本中,您创建了一个lazy bytestring。
print test1
强制它,但它不能被GC'ed,因为它是
print test2
所需要的:我不确定我是否完全理解这一点
longByteStr
仅用于
test1
,而不用于
test2
@artella-Hmm。。是的,我错过了,对不起。但是我不能用
ghc-7.6
复制它。您使用的编译器版本是什么?您好,我在Ubuntu 64位上使用了
ghc-7.8.2
,我已经测试了好几次,并且可以一致地复制它。我使用的是
7.6.3
,我用
7.8.2
复制了它。看看最新的答案。啊,真狡猾。我没有意识到这种优化。我已经通过将
Explode.hs中的
test2
表达式中的
abc
更改为
def
间接验证了这一点,在这种情况下,程序不再爆炸!谢谢