16
$\begingroup$

I'd like to make a graphical version of

Dynamic[Refresh[MemoryInUse[], UpdateInterval -> 1]]

A naive implementation would be something like:

miu = {};
Dynamic[Refresh[ListPlot[AppendTo[miu, MemoryInUse[]]], UpdateInterval -> 1]]

(Evaluate Quit[], or equivalently, choose Evaluation > Quit Kernel, to stop it.)

This code produces a very lousy memory monitor, because it, all by itself, causes the memory to grow steadily. IOW, it's a honking memory leak.

I tried something that I thought would be more conservative:

nReadings = 100;
miu = Table[0, nReadings];
i = 0;
updatemiu[] := Module[{},
  i = Mod[i, nReadings] + 1;
  miu[[i]] = MemoryInUse[];
  Join[Drop[miu, i], Take[miu, i]]
  ]

Dynamic[Refresh[ListPlot[updatemiu[]], UpdateInterval -> 1]]

This one leaks too, even though, in contrast to the previous version, it gets its data from a fixed-size list.

Is there a reliable way to cap the amount of memory used by this monitor?

$\endgroup$
  • 12
    $\begingroup$ wolfram.com/xid/0dh13vea48xsy-op8fal $\endgroup$ – Karsten 7. Oct 30 '15 at 0:42
  • 1
    $\begingroup$ @Karsten7. Great find (+1). It does, however, consume a fair bit of CPU time. $\endgroup$ – bbgodfrey Oct 30 '15 at 1:23
  • 1
    $\begingroup$ @bbgodfrey. I think the CPU load would be much reduced by raising the value given to the UpdateInterval option. I would be satisfied with an interval of 30 sec. rather than the 1 sec. used in the example. I would also consider raising the memory limit from 2 GB to something like 8GB. $\endgroup$ – m_goldberg Oct 30 '15 at 3:02
  • $\begingroup$ @Karsten7. When I click the Quit Kernel menu with that panel opened, the FrontEnd froze.. $\endgroup$ – Silvia Oct 30 '15 at 3:56
  • 1
    $\begingroup$ If you add TrackedSymbols :> {} to Dynamic and change MemoryInUse[] to N@MemoryInUse[] your last code block does work without "leakage". $\endgroup$ – Karsten 7. Nov 1 '15 at 8:09
10
$\begingroup$

As a Palette

1) Using ListLinePlot:

CreatePalette[{
  DynamicModule[{miu, timeStep = 0.1},
   Grid[{
     {Row[{"Current MemoryInUse [MiB]: ", 
        Dynamic[Style[miu[[-1]], Bold], TrackedSymbols :> {miu}]}],
      Item[Row[{"time step: ", RadioButtonBar[Dynamic[timeStep], {0.1, 0.5, 1}], 
         Spacer[35]}], Alignment -> Right]},
     {Dynamic[
       ListLinePlot[
        miu = Append[Drop[miu, 1], MemoryInUse[]/1024.^2.], 
        Frame -> True, FrameTicks -> {{None, All}, {True, None}}, 
        ImageSize -> 500, PlotRange -> All],
       TrackedSymbols :> {}, UpdateInterval -> timeStep, 
       Initialization :> (miu = ConstantArray[MemoryInUse[]/1024.^2., 500]; 
        timeStep = 0.1;)], 
      SpanFromLeft}}, Spacings -> {0, 0}]],
  CancelButton["Close", DialogReturn[]]},
 WindowTitle -> "Kernel Memory Usage"]

enter image description here

2) Using Graphics and additional styling:

CreatePalette[{
  DynamicModule[{miu, timeStep, xRange},
   Grid[{
     {Row[{"Current MemoryInUse [MiB]: ", 
        Dynamic[Style[miu[[-1]], Bold], TrackedSymbols :> {miu}]}],
      Item[
       Row[{"time step: ", RadioButtonBar[Dynamic[timeStep], {0.03, 0.1, 0.5, 1}], 
         Spacer[32]}], Alignment -> Right]},
     {Graphics[{Hue[0.5908], 
        Line[Dynamic[
          Refresh[Thread[{xRange, miu = Append[Drop[miu, 1], MemoryInUse[]/1024.^2.]}], 
           TrackedSymbols :> {}, UpdateInterval -> timeStep], None, 
          TrackedSymbols :> {}, UpdateInterval -> Infinity]]}, 
       Frame -> True, FrameTicks -> {{None, All}, {True, None}}, 
       AspectRatio -> 1/GoldenRatio, ImageSize -> 500, 
       PlotRange -> All, FrameStyle -> GrayLevel[0.5]], SpanFromLeft}
     }, Spacings -> {0, 0}, BaseStyle -> {GrayLevel[0.5]}], 
   Initialization :> (miu = ConstantArray[MemoryInUse[]/1024.^2., 500]; 
      xRange = Range[500]; timeStep = 0.1)],
  CancelButton["Close", DialogReturn[]]}, 
 Background -> GrayLevel[0.17], WindowTitle -> "Kernel Memory Usage", 
 WindowFrame -> "Frameless", WindowFloating -> True, 
 WindowClickSelect -> False, Deployed -> True]

Animation2

| improve this answer | |
$\endgroup$
6
$\begingroup$

Using Graphics directly instead of *Plot should give a better performance. The following code with timeStep set to 0.1 consumes less than 10% CPU on my laptop.

Click the graphics to pause, click again to resume, click the "Truncate to ..." button to truncate the record:

DynamicModule[{miu, flag = True, timeStep = .1},
    Module[{startTime = AbsoluteTime[], postlen = 10, maxlen = 200},
        miu = {{AbsoluteTime[] - startTime, MemoryInUse[]/1024^2 // N}};
        Pause[timeStep];
        DynamicWrapper[
            Column[{
                    Button[
                        Deploy@Graphics[{
                                    Line[Dynamic[miu, TrackedSymbols :> {miu}]]
                                    }, AspectRatio -> 1/GoldenRatio, Frame -> True, 
                                FrameTicks -> {{None, All}, {True, None}},
                                ImageSize -> 400,
                                Background -> 
                                    Dynamic[If[flag, White, GrayLevel[.95]], 
                                        TrackedSymbols :> {flag}]
                                ],
                        flag = ! flag,
                        Appearance -> "Frameless"],
                    Button[
                        Row[{"Truncate to ", "〚", postlen, 
                                ";;〛"}],
                        If[Length[miu] > postlen, miu = miu[[postlen ;;]]]
                        ],
                    Button[
                        Row[{"Truncate to ", "〚-", maxlen, 
                                ";;〛"}],
                        If[Length[miu] > maxlen, miu = miu[[-maxlen ;;]]]
                        ]
                    }],
            If[flag,
                Refresh[
                    miu = 
                        Join[miu, {{AbsoluteTime[] - startTime, (
                                        MemoryInUse[] - ByteCount[miu])/1024^2 // N}}],
                    UpdateInterval -> timeStep]
                ],
            TrackedSymbols :> {flag}
            ]
        ]
    ]

simple memory monitor

| improve this answer | |
$\endgroup$
5
$\begingroup$

This is more an extended comment than an answer. A compact version of the code given in the question is

miu = Table[0, 150]; memmin = MemoryInUse[]; memmax = memmin + 10^7;
Dynamic[Refresh[miu = Append[Drop[miu, 1], MemoryInUse[]]; 
    ListPlot[miu, PlotRange -> {memmin, memmax}], UpdateInterval -> 1, 
    TrackedSymbols :> {}]]

(A small PlotRange is chosen here to emphasize the memory growth.) Run for ten minutes on my four-processor, Mathematica consumes about 20% more memory than when it started, from about 50000 to nearly 60000 kB.

enter image description here

CPU utilization is negligible. Note that TrackedSymbols :> {} is essential; without it memory growth is far greater and CPU utilization jumps to nearly 20%.

The sample Wolfram code identified by Karsten 7, on the other hand, produces only minor memory growth, although with nearly 20% CPU utilization. Of course, a larger UpdateInterval would reduce CPU utilization, as commented by m_goldberg. A larger UpdateInterval also would reduce memory growth for the code above.

| improve this answer | |
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.