views:

81

answers:

3

I'm used to debug my code using ghci. Often, something like this happens (not so obvious, of course):

ghci> let f@(_:x) = 0:1:zipWith(+)f x
ghci> length f

Then, nothing happens for some time, and if I don't react fast enough, ghci has eaten maybe 2 GB of RAM, causing my system to freeze. If it's too late, the only way to solve this problem is [ALT] + [PRINT] + [K].

My question: Is there an easy way to limit the memory, which can be consumed by ghci to, let's say 1 GB? If limit is exceed, the calculation should ve aborted or ghci should be killed.

+1  A: 

GHC has the -M option that limits the heap site, but it doesn't work for me for GHCi:

C:\Users\Svick>ghci -M1M
GHCi, version 6.10.2: http://www.haskell.org/ghc/  :? for help
: unrecognised flags: -M1M
Usage: For basic information, try the `--help' option.

EDIT: AS @Bas Bossink pointed out in a comment below, it's ghci +RTS -M1M.

svick
Why should I want to know, what is *not* possible? -1
FUZxxl
You need to supply the -M option as an option to the runtime system using `ghci +RTS -M1m`
Bas Bossink
@FUZxxl, because it might point you (or others) in the right direction.
svick
@Bas Bossink: perfect. Works for me
FUZxxl
@svick: Change your answer, so I can change my downvote into an upvote.
FUZxxl
+1  A: 

Running it under a shell with ulimit -m set is a fairly easy way. If you want to run with some limit on a regular basis, you can create a wrapper script that does ulimit before running ghci.

hobbs
This doesn't works. I tried something like `ulimit -m 102400` and it still consumes memory.
FUZxxl
@hobbs @FUZxxl you should use `ulimit -v`, not `ulimit -m`. `-m` switch limits physical memory, while you need to limit virtual: physical+swap. I use `ulimit -v $(( (1024**2)*2 ))` (zsh) with 4 GiB RAM + 5 GiB swap and it does not freeze the system. This limits the amount of memory to 2 GiB and can be put into `~/.zshrc` or `~/.bashrc`.
ZyX
Thank you. I find this less helpfull, as I cannot change the value in the shell again afterwards. (Only down...)
FUZxxl
@FUZxxl Why you can't? I have no problems with this (or did you mean that you can't change it from GHCi?). It may be less useful because when the process runs out of memory, it may catch SEGV and crash, but GHCi is handling this normally. There is some related useful feature in zsh: if some application that is modifying tty settings (for example, vim) crashes, you will get a mess on the screen and have some keys not working. Zsh builtin `ttyctl` with argument `-f` will prevent this.
ZyX
What I mean is like this: First, I do something like `ulimit -v 102400`, then - after ghci - I want to undo: `ulimit -v unlimited`, but I get a permission error.
FUZxxl
@FUZxxl I can suggest switching to zsh: I managed to reproduce your problem, but on bash only.
ZyX
@ZyX I'm too lazy.
FUZxxl
In bash you can use parentheses to spawn a subshell, so this should set a ulimit which applies to ghci only and is lifted when the subshell exits: $ (ulimit -v 1000000; ghci)
cthulahoops
+5  A: 

A platform independant way to accomplish this is to supply the -M option as on option to the Haskell runtime like this

ghci +RTS -M1m

see here for details.

The ghci output now looks like:

>ghci +RTS -M10m
GHCi, version 6.12.3: http://www.haskell.org/ghc/  :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
Loading package ffi-1.0 ... linking ... done.
Prelude> let f@(_:x) = 0:1:zipWith(+)f x
Prelude> length f
Heap exhausted;
Current maximum heap size is 10485760 bytes (10 MB);
use `+RTS -M<size>' to increase it.
Bas Bossink
I just created an alias `alias ghci='ghci +RTS -M500m -RTS'` in `~/.bashrc` and anything is fine now. Thank you very much.
FUZxxl