Q1) Why is the memory consumed so large? I see that the amount of allocated memory is ~ 100 MB, but the actual size of the input is 5 MB.
Haskell's String is an alias of type [Char] , so by actual bytes the compiler must also contain a constructor, a pointer to a field character and a pointer to the next constructor for each character in memory, results> 10 times of memory use than a C-style string. Even worse that text is stored several times in memory.
Q3) How can I process two lines with constant memory, for example, the last execution schedule?
Q4) If the answer to Q3) depends on the processing order, how can I process the second line first and then the first line?
No, you cannot process the second line first, since the lines function must evaluate each byte in the first line to get into the new line character \ n.
Q2) Does head xs force the entire first line to be read into memory, even secondLine is not used at all? And is this the main reason for the increase in the heap profile graph memory?
This is not the head that prevents GCL. A space leak still occurs if you configure a signature like doSomething and pass xs directly to it. The fact is that the compiler (not optimizing) will not know that secondLine not used before doSomething finally hits the first template, so the program saves a link to xs . BTW, if compiled with -O2, your program works with read-only memory.
What caused your program space to leak, basically this line:
let (x:xs) = lines inputdata
If either x or xs discarded, this let clause will be aligned in the dumped kernel. Only when both of them are referenced later, Core behaves strangely: it builds a tuple, destroys it by matching patterns, and then converts the two parts into a tuple again, therefore, preserving the link to secondLine , the program actually saves the link to the tuple (x, xs) , so the first line will never be GCed.
The kernel with secondLine commented out:
Rec { doSomething_rjH doSomething_rjH = \ ds_d1lv y_alG -> case ds_d1lv of _ { [] -> I# 0; : x_alH xs_alI -> doSomething_rjH xs_alI y_alG } end Rec } main main = >>= $fMonadIO getContents (\ inputdata_app -> print $fShowInt (doSomething_rjH (map (read $fReadInt) (words (case lines inputdata_app of _ { [] -> case irrefutPatError "a.hs:6:9-32|(x : xs)"# of wild1_00 { }; : x_auf xs_aug -> x_auf }))) ([]))) main main = runMainIO main
Space leak kernel:
Rec { doSomething_rjH doSomething_rjH = \ ds_d1ol y_alG -> case ds_d1ol of _ { [] -> I# 0; : x_alH xs_alI -> doSomething_rjH xs_alI y_alG } end Rec } main main = >>= $fMonadIO getContents (\ inputdata_app -> -- *** Construct *** let { ds_d1op ds_d1op = case lines inputdata_app of _ { [] -> irrefutPatError "a.hs:6:9-30|x : xs"#; : x_awM xs_awN -> (x_awM, xs_awN) } } in -- *** Destruct *** let { xs_awN xs_awN = case ds_d1op of _ { (x_awM, xs1_XwZ) -> xs1_XwZ } } in let { x_awM x_awM = case ds_d1op of _ { (x1_XwZ, xs1_XwU) -> x1_XwZ } } in -- *** Construct *** let { ds1_d1oq ds1_d1oq = (x_awM, xs_awN) } in print $fShowInt -- *** Destruct *** (doSomething_rjH (map (read $fReadInt) (words (case ds1_d1oq of _ { (x1_Xx1, xs1_Xx3) -> x1_Xx1 }))) (map (read $fReadInt) (words (head (case ds1_d1oq of _ { (x1_Xx1, xs1_Xx3) -> xs1_Xx3 })))))) main main = runMainIO main
Replace the let clause with the case .. of clause, fix the space leak:
doSomething :: [Int] -> [Int] -> Int doSomething [] _ = 0 -- stop execution. I'm concerted in memory behavior only. doSomething (_:xs) y = doSomething xs y main :: IO () main = do inputdata <- getContents case lines inputdata of x:xs -> do let firstLine = map (read ::String->Int) $ words x secondLine = map (read ::String->Int) $ words $ head xs print $ doSomething firstLine secondLine
The dropped kernel. This time the picture βbuild and then destroyβ did not happen:
Rec { doSomething_rjG doSomething_rjG = \ ds_d1o6 ds1_d1o7 -> case ds_d1o6 of _ { [] -> I# 0; : ds2_d1o8 xs_alG -> doSomething_rjG xs_alG ds1_d1o7 } end Rec } main main = >>= $fMonadIO getContents (\ inputdata_apn -> case lines inputdata_apn of _ { [] -> patError "a.hs:(8,3)-(13,46)|case"#; : x_asI xs_asJ -> print $fShowInt (doSomething_rjG (map (read $fReadInt) (words x_asI)) (map (read $fReadInt) (words (head xs_asJ)))) }) main main = runMainIO main