View Javadoc
1   /*
2    * Copyright 2016-2022 The OSHI Project Contributors
3    * SPDX-License-Identifier: MIT
4    */
5   package oshi.hardware.platform.linux;
6   
7   import static oshi.util.Memoizer.defaultExpiration;
8   import static oshi.util.Memoizer.memoize;
9   
10  import java.util.List;
11  import java.util.function.Supplier;
12  
13  import oshi.annotation.concurrent.ThreadSafe;
14  import oshi.hardware.VirtualMemory;
15  import oshi.hardware.common.AbstractGlobalMemory;
16  import oshi.software.os.linux.LinuxOperatingSystem;
17  import oshi.util.FileUtil;
18  import oshi.util.ParseUtil;
19  import oshi.util.platform.linux.ProcPath;
20  import oshi.util.tuples.Pair;
21  
22  /**
23   * Memory obtained by /proc/meminfo and sysinfo.totalram
24   */
25  @ThreadSafe
26  public final class LinuxGlobalMemory extends AbstractGlobalMemory {
27  
28      private static final long PAGE_SIZE = LinuxOperatingSystem.getPageSize();
29  
30      private final Supplier<Pair<Long, Long>> availTotal = memoize(LinuxGlobalMemory::readMemInfo, defaultExpiration());
31  
32      private final Supplier<VirtualMemory> vm = memoize(this::createVirtualMemory);
33  
34      @Override
35      public long getAvailable() {
36          return availTotal.get().getA();
37      }
38  
39      @Override
40      public long getTotal() {
41          return availTotal.get().getB();
42      }
43  
44      @Override
45      public long getPageSize() {
46          return PAGE_SIZE;
47      }
48  
49      @Override
50      public VirtualMemory getVirtualMemory() {
51          return vm.get();
52      }
53  
54      /**
55       * Updates instance variables from reading /proc/meminfo. While most of the information is available in the sysinfo
56       * structure, the most accurate calculation of MemAvailable is only available from reading this pseudo-file. The
57       * maintainers of the Linux Kernel have indicated this location will be kept up to date if the calculation changes:
58       * see https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?
59       * id=34e431b0ae398fc54ea69ff85ec700722c9da773
60       * <p>
61       * Internally, reading /proc/meminfo is faster than sysinfo because it only spends time populating the memory
62       * components of the sysinfo structure.
63       *
64       * @return A pair containing available and total memory in bytes
65       */
66      private static Pair<Long, Long> readMemInfo() {
67          long memFree = 0L;
68          long activeFile = 0L;
69          long inactiveFile = 0L;
70          long sReclaimable = 0L;
71  
72          long memTotal = 0L;
73          long memAvailable;
74  
75          List<String> procMemInfo = FileUtil.readFile(ProcPath.MEMINFO);
76          for (String checkLine : procMemInfo) {
77              String[] memorySplit = ParseUtil.whitespaces.split(checkLine, 2);
78              if (memorySplit.length > 1) {
79                  switch (memorySplit[0]) {
80                  case "MemTotal:":
81                      memTotal = ParseUtil.parseDecimalMemorySizeToBinary(memorySplit[1]);
82                      break;
83                  case "MemAvailable:":
84                      memAvailable = ParseUtil.parseDecimalMemorySizeToBinary(memorySplit[1]);
85                      // We're done!
86                      return new Pair<>(memAvailable, memTotal);
87                  case "MemFree:":
88                      memFree = ParseUtil.parseDecimalMemorySizeToBinary(memorySplit[1]);
89                      break;
90                  case "Active(file):":
91                      activeFile = ParseUtil.parseDecimalMemorySizeToBinary(memorySplit[1]);
92                      break;
93                  case "Inactive(file):":
94                      inactiveFile = ParseUtil.parseDecimalMemorySizeToBinary(memorySplit[1]);
95                      break;
96                  case "SReclaimable:":
97                      sReclaimable = ParseUtil.parseDecimalMemorySizeToBinary(memorySplit[1]);
98                      break;
99                  default:
100                     // do nothing with other lines
101                     break;
102                 }
103             }
104         }
105         // We didn't find MemAvailable so we estimate from other fields
106         return new Pair<>(memFree + activeFile + inactiveFile + sReclaimable, memTotal);
107     }
108 
109     private VirtualMemory createVirtualMemory() {
110         return new LinuxVirtualMemory(this);
111     }
112 }