Performance 在Haskell'中强制顺序处理;s Data.Binary.Get
在尝试用Java类文件语言导入基本Java运行时库rt.jar之后,我发现它使用了大量内存 我已经将演示该问题的程序减少到100行,并将其上载到。如果不强制在第94行中计算Performance 在Haskell'中强制顺序处理;s Data.Binary.Get,performance,haskell,lazy-evaluation,Performance,Haskell,Lazy Evaluation,在尝试用Java类文件语言导入基本Java运行时库rt.jar之后,我发现它使用了大量内存 我已经将演示该问题的程序减少到100行,并将其上载到。如果不强制在第94行中计算流,我就没有机会运行它,因为它会耗尽我所有的内存。在将流传递给getClass之前强制执行stream完成,但仍然会占用大量内存: 34,302,587,664 bytes allocated in the heap 32,583,990,728 bytes copied during GC 139,810,
流
,我就没有机会运行它,因为它会耗尽我所有的内存。在将流传递给getClass
之前强制执行stream
完成,但仍然会占用大量内存:
34,302,587,664 bytes allocated in the heap
32,583,990,728 bytes copied during GC
139,810,024 bytes maximum residency (398 sample(s))
29,142,240 bytes maximum slop
281 MB total memory in use (4 MB lost due to fragmentation)
Generation 0: 64992 collections, 0 parallel, 38.07s, 37.94s elapsed
Generation 1: 398 collections, 0 parallel, 25.87s, 27.78s elapsed
INIT time 0.01s ( 0.00s elapsed)
MUT time 37.22s ( 36.85s elapsed)
GC time 63.94s ( 65.72s elapsed)
RP time 0.00s ( 0.00s elapsed)
PROF time 13.00s ( 13.18s elapsed)
EXIT time 0.00s ( 0.00s elapsed)
Total time 114.17s (115.76s elapsed)
%GC time 56.0% (56.8% elapsed)
Alloc rate 921,369,531 bytes per MUT second
Productivity 32.6% of total user, 32.2% of total elapsed
我认为问题在于ConstTable
s停留在附近,所以我尝试强制cls
在第94行。但这只会使内存消耗和运行时变得更糟:
34,300,700,520 bytes allocated in the heap
23,579,794,624 bytes copied during GC
487,798,904 bytes maximum residency (423 sample(s))
36,312,104 bytes maximum slop
554 MB total memory in use (10 MB lost due to fragmentation)
Generation 0: 64983 collections, 0 parallel, 71.19s, 71.48s elapsed
Generation 1: 423 collections, 0 parallel, 344.74s, 353.01s elapsed
INIT time 0.01s ( 0.00s elapsed)
MUT time 40.60s ( 42.38s elapsed)
GC time 415.93s (424.49s elapsed)
RP time 0.00s ( 0.00s elapsed)
PROF time 56.53s ( 57.71s elapsed)
EXIT time 0.00s ( 0.00s elapsed)
Total time 513.07s (524.58s elapsed)
%GC time 81.1% (80.9% elapsed)
Alloc rate 844,636,801 bytes per MUT second
Productivity 7.9% of total user, 7.7% of total elapsed
因此,我的问题基本上是,如何强制对涉及的文件进行顺序处理,以便在处理完每个文件后,只有字符串结果(
cls
)保留在内存中?编辑2:我刚刚意识到您的代码会这样做:
stream <- BL.pack <$> fileContents [] classfile
可能有必要使用deepseq
而不仅仅是seq
,尽管我怀疑简单的seq
在这里就足够了
然而,我认为有一个更好的解决方案,那就是使用mapM\uu
而不是mapM
。我认为创建一个函数来处理每个结果,而不是返回一个列表,通常是更好的风格(而且几乎总是更好的性能)。在此,您可以将主要功能更改为:
main = do
withArchive [CheckConsFlag] jarPath $ do
classfiles <- filter isClassfile <$> fileNames []
forM_ classfiles $ \classfile -> do
stream <- BL.pack <$> fileContents [] classfile
let cls = runGet getClass stream
lift $ print cls
main=do
withArchive[CheckConsFlag]jarPath$do
类文件做什么
谢谢你的建议
我认为对于我的具体问题,解决方案将是以小块方式处理.jar文件——幸运的是,内部类在.jar文件中总是与其外部类位于同一目录中,因此不需要在一次运行中处理所有50个meg
我唯一不能完全理解的是,是否可以通过枚举器使用libzip,或者是否需要一个新的libzip实现?您在第94行强制计算cls的想法是正确的。但我猜你们的方法并没有成功。我的版本是40MB,而不是220MB
关键是强制还原到cls的正常形式,这是由rnf cls完成的。这必须在电话返回之前发生。因此:
rnf cls`seq`返回cls
或者,您可以使用Control.Exception.evaluate:
评估$rnf cls
return cls您如何进行堆分析并在问题中发布该图。我已将这两个版本的堆分析输出添加到hpaste。您是否尝试过使用grane
包?这只是一个想法,但是如果你知道文件足够小,严格的ByTestRing通常会有所帮助。我对谷物
有两个问题:一个是它似乎不支持固定字节顺序的浮动,另一个是缺少MonadFix实例。但是在实际的程序中,我的结果是cls的列表。另外,第二个输出来自streamseq
clsseq
return cls(如果我不够清楚,很抱歉)@Cactus,很抱歉,我刚刚在我的答案顶部添加了一个注释,请检查。另外,我知道您的结果是cls的列表,但我认为最好是创建一个函数来处理每个cls,而不是创建一个cls列表。但我不认为这是最重要的问题。我使用的模块来自Binary、data-Binary-ieee754、bytestring、containers、missingh和libzip(希望我没有遗漏任何模块),我应该使用什么来代替BL.pack?使用BS.pack和BL.fromChunks会有帮助吗?
main = do
withArchive [CheckConsFlag] jarPath $ do
classfiles <- filter isClassfile <$> fileNames []
forM_ classfiles $ \classfile -> do
stream <- BL.pack <$> fileContents [] classfile
let cls = runGet getClass stream
lift $ print cls