34
$\begingroup$

Is there any way in Mathematica to find out the currently free memory on the system Mathematica runs on (like the utility free shows on the command line)? I've found out functions to show the memory occupied by Mathematica itself, but of course there are also other programs running on the system, taking their share of memory, so that number is not sufficient to estimate the free memory.

The background is that currently if I do something which might fill up my memory (and I don't forget to do it), I call free by hand, subtract a safety margin, and then use MemoryConstrained in order to prevent the memory to get completely filled up (with quite unpleasant consequences). I'd like to automate that. While I certainly could call free from Mathematica and parse its output for the number, I'd like to avoid that if I can (who knows if the next system update makes subtle changes to free and then the parsing fails to give the correct number).

$\endgroup$
8
  • 1
    $\begingroup$ this seems os-specific. maybe tag it as such if it is $\endgroup$
    – acl
    Jan 18, 2012 at 14:59
  • $\begingroup$ Well, MemoryInUse[] is the polar opposite of free, I'd say... $\endgroup$ Jan 18, 2012 at 15:00
  • 1
    $\begingroup$ @acl: Well, the concept of free memory is certainly not OS specific. The free utility is, but I'm after a Mathematica function (if it exists) which most likely wouldn't be (I don't think there is any OS Mathematica runs on where you cannot get an estimate of available memory). Of course, if none exists, my workaround (parsing output of free) would be OS specific, but that's not what I asked for (although if someone wants to write it for me, I wouldn't complain :-)). So the OS-independent answer would be either "The function is called so-and-so and used like this" or "There isn't any." $\endgroup$
    – celtschk
    Jan 18, 2012 at 15:08
  • $\begingroup$ @R.M: I'd not expect Mathematica to add memory of all processes (I strongly doubt free does that either). I think that every OS will have some functionality to estimate free memory (guarantees cannot be given anyway because right after returning, another process might allocate memory), and I'd expect Mathematica to use that functionality. $\endgroup$
    – celtschk
    Jan 18, 2012 at 15:11
  • 1
    $\begingroup$ fair enough. I doubt there is an OS-independent way of doing it, though. $\endgroup$
    – acl
    Jan 18, 2012 at 15:19

6 Answers 6

27
$\begingroup$

You might be able to use JLink along with some undocumented behaviour of the Java class java.lang.management.ManagementFactory to get the information you seek:

Needs["JLink`"]
InstallJava[];
LoadJavaClass["java.lang.management.ManagementFactory"];
JavaBlock[
  {#, java`lang`management`ManagementFactory`getOperatingSystemMXBean[]@#[]} & /@
  { getName
  , getArch
  , getVersion
  , getCommittedVirtualMemorySize
  , getFreePhysicalMemorySize
  , getFreeSwapSpaceSize
  , getTotalPhysicalMemorySize
  , getTotalSwapSpaceSize
  , getProcessCpuTime
  , getAvailableProcessors
  , getSystemLoadAverage
  } // Grid
]

This works on Windows 7 (Mathematica 8, 64-bit):

Out[368]= getName                        Windows Vista
          getArch                        amd64
          getVersion                     6.1
          getCommittedVirtualMemorySize  102449152
          getFreePhysicalMemorySize      5997510656
          getFreeSwapSpaceSize           14498115584
          getTotalPhysicalMemorySize     8587284480
          getTotalSwapSpaceSize          17172676608
          getProcessCpuTime              6068438900
          getAvailableProcessors         4
          getSystemLoadAverage           -1.

I don't have Mac or Linux boxes to hand at the moment to test whether it works there as well.

$\endgroup$
9
  • 1
    $\begingroup$ it works fine on OS X (your system is not only not being loaded, but in fact actively doing negative work???) $\endgroup$
    – acl
    Jan 21, 2012 at 20:18
  • 5
    $\begingroup$ @acl Thanks for checking OS X. As for the negative work, everybody complains about the heat death of the universe but few do anything about it ;) $\endgroup$
    – WReach
    Jan 21, 2012 at 20:28
  • 1
    $\begingroup$ Do you know why this shows Windows Vista and amd64? $\endgroup$
    – Mr.Wizard
    Jan 22, 2012 at 7:41
  • 2
    $\begingroup$ @Mr.Wizard Windows 7 is a really just a marketing label slapped on a Vista release. It would seem that the name change happened too late to change it in the deepest parts of the OS. "amd64" is the name given to the original 64-bit instructions added to the x86 architecture. The name has stuck, although the term "x86-64" is sometimes used as a vendor-neutral term. It so happens that this workstation has an Intel CPU, not an AMD one, but the historical term is used nonetheless. $\endgroup$
    – WReach
    Jan 22, 2012 at 16:31
  • 1
    $\begingroup$ I've just checked on Linux, it works there as well. Moreover, the output is a Grid instead of simply a string, thus parsing isn't necessary either. I've changed the accepted answer to yours. $\endgroup$
    – celtschk
    Jan 22, 2012 at 20:58
6
$\begingroup$

On Windows with an external call:

ReadList["!typeperf \"\\Memory\\Available Bytes\" -sc 1", Word, 
   RecordLists -> True, WordSeparators -> {","}] // ToExpression@Part[#,2,2]&
$\endgroup$
1
  • 1
    $\begingroup$ +1. Great! But it does not work for localized versions of Windows: words "Memory" and "Available Bytes" are localized and English version does not work. For getting localized names one can use the typeperf -qx command. $\endgroup$ Aug 19, 2012 at 14:29
6
$\begingroup$

Under Windows you can use NETLink for this (it requires Microsoft .NET v.2 or later to be installed). Two methods were discussed in this MathGroups thread: "Calling kernel.dll from Mathematica. 1", "Calling kernel.dll from Mathematica. 2".

One way is to get this information via a managed API (that is, in .NET itself):

Needs["NETLink`"]
query = NETNew["System.Management.ManagementObjectSearcher", 
   "SELECT * FROM Win32_OperatingSystem"];
resultCollection = query@Get[];
mo = First[NETObjectToExpression[resultCollection]];
getFreePhysMemNet[] := (mo@Get[]; mo["FreePhysicalMemory"])

The function getFreePhysMemNet[] returns the amount of free physical memory in Kb. This method is 30 times slower than direct calling of the GlobalMemoryStatusEx function of kernel32.dll which is availiable both on 32 bit and 64 bit Windows systems (checked under Windows 7 x64). Here is the code:

Needs["NETLink`"];
getFreePhysMem::internalError = 
  "globalMemoryStatusEx[memorystatusex] has not returned True.";
If[$OperatingSystem === "Windows", 
      memorystatusex = Symbol["LoadedNETTypes"][];
      globalMemoryStatusEx = 
       Symbol["DefineDLLFunction"][
        "[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)]
                public class MEMORYSTATUSEX
                {public uint dwLength;
                public uint dwMemoryLoad;
                public ulong ullTotalPhys;
                public ulong ullAvailPhys;
                public ulong ullTotalPageFile;
                public ulong ullAvailPageFile;
                public ulong ullTotalVirtual;
                public ulong ullAvailVirtual;
                public ulong ullAvailExtendedVirtual;
                public MEMORYSTATUSEX()
                {this.dwLength = (uint) 
                Marshal.SizeOf(typeof( MEMORYSTATUSEX ));}}
                [return: MarshalAs(UnmanagedType.Bool)]
                [DllImport(\"kernel32.dll\", CharSet=CharSet.Auto,     \
    SetLastError=true)]
                public static extern bool GlobalMemoryStatusEx([In, Out]  \
       MEMORYSTATUSEX lpBuffer);"];
      memorystatusex = 
       Complement[Symbol["LoadedNETTypes"][], memorystatusex][[1, 1]];
      memorystatusex = memorystatusex <> "+MEMORYSTATUSEX";
      memorystatusex = Symbol["NETNew"][memorystatusex];
      getFreePhysMem[] := 
       If[TrueQ[globalMemoryStatusEx[memorystatusex]], 
        memorystatusex@ullAvailPhys, 
        Message[getFreePhysMem::internalError]; Abort[]; $Failed]];

The function getFreePhysMem[] returns the amount of free physical memory in bytes.

Timings:

In[10]:= Do[getFreePhysMemNet[], {100}] // AbsoluteTiming
Do[getFreePhysMem[], {100}] // AbsoluteTiming
%%/%

Out[10]= {1.9218750, Null}

Out[11]= {0.0625000, Null}

Out[12]= {30.7500, 1}
$\endgroup$
5
$\begingroup$

Since Mathematica runs on only a few different OS's, why not write a little conditional expression that, for each OS, feeds to a shell the corresponding command that returns the amount of free memory.

The trouble, of course, is that not all OS's are equal in this regard. I don't know of a Mac OS X built-in command equivalent to the Linux free, but you can locate Python scripts that will do the equivalent thing.

$\endgroup$
1
  • $\begingroup$ Given that until now nobody has told me one, I have to conclude that there's indeed no ready-made Mathematica function (or if there is, it's so hidden in undocumented internals that nobody knows about it), therefore I accept your answer as the right one. $\endgroup$
    – celtschk
    Jan 19, 2012 at 5:58
2
$\begingroup$

Well,for the efficiency I will give a new version:

Last[ReadList["!wmic OS get FreePhysicalMemory"]]

PS:I just test it in my windows 10.You can check it in your environment.

$\endgroup$
1
$\begingroup$

If you're on a Mac, you can call the external command vm_stat with RunProcess:

RunProcess["vm_stat"]

enter image description here

We can extract the relevant data in lines 1 and 2 to get the available memory on the system. Here it is packed into a function:

AvailableSystemMemory[] /; $OperatingSystem == "MacOSX" :=
  Module[{call, vmstat, bytesperpage, pagesfree},

    call = RunProcess["vm_stat"];
    vmstat = call["StandardOutput"];

    (
        bytesperpage = StringCases[vmstat, "(page size of " ~~ x__ ~~ " bytes)" :> Quantity[ToExpression[x], "Bytes"]];
        pagesfree = StringCases[vmstat, "Pages free:" ~~ Shortest[x__] ~~ "\n" :> ToExpression[x]];

        (
            UnitConvert[First[bytesperpage pagesfree], "Gigabytes"]

        ) /; Length[bytesperpage] == Length[pagesfree] == 1

    ) /; call["ExitCode"] == 0 && call["StandardError"] == "" && StringQ[vmstat]
  ]

Memory available on my machine:

AvailableSystemMemory[]
Quantity[8.42319, "Gigabytes"]
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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