9

I am writing a Python script which downloads 4K videos and plays them on request. When my device memory goes above 7.2 GB it deletes the video with the least number of views.

Using the free command or top command I can get the memory information. But specifically, how do I get the total memory used? So that I can return this to the Python function to compare with the memory threshold.

1
10

Percentage used memory (excluding buffers and cache):

free | awk 'FNR == 3 {print $3/($3+$4)*100}'

For your question you added: "above 7.2 gigabyte", but I would assume a percentage might be more flexible.


To expand on this, the same can be used for "percentage free memory":

free | awk 'FNR == 3 {print $4/($3+$4)*100}'

awk is a pattern scanning tool with loads and loads of parameters. FNR is the input record number in the current input file. Basically the line that is currently processed. So FNR will scan for the 3rd line where the numbers are what you want. The $3 and $4 point to the 3rd and 4th column. If you want the number itself, use:

free | awk 'FNR == 3 {print $3}'
free | awk 'FNR == 3 {print $4}'

Example:

$ free
             total       used       free     shared    buffers     cached
Mem:      16419996   16144316     275680          0     447220   12589412
-/+ buffers/cache:    3107684   13312312
Swap:     16761852      38532   16723320
~$ free | awk 'FNR == 3 {print $3}'
3109056
~$ free | awk 'FNR == 3 {print $4}'
13311240

If you want with buffers and cache: FNR=2. If you want swap, FNR=4.

19

You can also read the source of free's information, /proc/meminfo:

~ head /proc/meminfo
MemTotal:        4039168 kB
MemFree:         2567392 kB
MemAvailable:    3169436 kB
Buffers:           81756 kB
Cached:           712808 kB
SwapCached:            0 kB
Active:           835276 kB
Inactive:         457436 kB
Active(anon):     499080 kB
Inactive(anon):    17968 kB

In Python, for example:

with open('/proc/meminfo') as file:
    for line in file:
        if 'MemFree' in line:
            free_mem_in_kb = line.split()[1]
            break

will get you the free memory in KB in the free_mem_in_kb variable. With something similar for total memory, you can subtract the values (or add up buffers, cached, etc.).

You could also create a dictionary of the values in the file:

from collections import namedtuple
MemInfoEntry = namedtuple('MemInfoEntry', ['value', 'unit'])

meminfo = {}
with open('/proc/meminfo') as file:
    for line in file:
        key, value, *unit = line.strip().split()
        meminfo[key.rstrip(':')] = MemInfoEntry(value, unit)

Then retrieve the values with meminfo['MemAvailable'].value, for example.

7
  • 4
    +1 - using /proc/meminfo is much more elegant that trying to parse the output of "free". Admittedly the format of free's output is unlikely to change now, but I recently had a script break horribly and make a service nonfunctional because it depended on awking the human-readable output of a different command, of which the format changed slightly due to the utility being updated. – Carcer Aug 8 '18 at 7:52
  • 3
    @Carcer "Admittedly the format of free's output is unlikely to change now ..." - Actually, exactly that happened about 4 years ago. Don't rely on parsing the output from such tools, if you can help it. – marcelm Aug 8 '18 at 12:42
  • 4
    @carcer Why is the output of /proc/meminfo less likely to change in the long term than that of free? The choice seems to be between parsing one or the other. – Federico Poloni Aug 8 '18 at 13:55
  • 4
    @FedericoPoloni because Linus hates changes that break userspace, and /proc/meminfo has been exposed to users for a very long time. – muru Aug 8 '18 at 14:05
  • 6
    @FedericoPoloni Note that /proc/meminfo is not meant for humans (who can cope with changes in output formatting), but for other programs (which might break on changes). Like muru notes, Linux kernel devs strive to not break userspace using documented APIs (of which /proc/meminfo is one). Additionally, the format for /proc/meminfo is more or less key-value pairs, so adding new fields can be done without breaking backwards compatibility. Breaking changes could still happen, but I do think they're less likely than for free. – marcelm Aug 8 '18 at 14:30
2

muru's Python code intrigued me to use it in a decorator class to measure memory consumption of a function.

class memoryit:

    def FreeMemory():
        with open('/proc/meminfo') as file:
            for line in file:
                if 'MemFree' in line:
                    free_memKB = line.split()[1]
                    return (float(free_memKB)/(1024*1024))    # returns GBytes float

    def __init__(self, function):    # Decorator class to print the memory consumption of a 
        self.function = function     # function/method after calling it a number of iterations

    def __call__(self, *args, iterations = 1, **kwargs):
        before = memoryit.FreeMemory()
        for i in range (iterations):
            result = self.function(*args, **kwargs)
        after = memoryit.FreeMemory()
        print ('%r memory used: %2.3f GB' % (self.function.__name__, (before - after) / iterations))
        return result

Function to measure consumption:

@memoryit
def MakeMatrix (dim):
    matrix = []   
    for i in range (dim):
        matrix.append([j for j in range (dim)])
    return (matrix)

Usage:

print ("Starting memory:", memoryit.FreeMemory()) 
m = MakeMatrix(10000)    
print ("Ending memory:", memoryit.FreeMemory() )

Printout:

Starting memory: 10.58599853515625
'MakeMatrix' memory used: 3.741 GB
Ending memory: 6.864116668701172

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.