2222import org .apache .iotdb .commons .service .metric .enums .Tag ;
2323import org .apache .iotdb .metrics .AbstractMetricService ;
2424import org .apache .iotdb .metrics .MetricConstant ;
25+ import org .apache .iotdb .metrics .config .MetricConfig ;
26+ import org .apache .iotdb .metrics .config .MetricConfigDescriptor ;
2527import org .apache .iotdb .metrics .metricsets .IMetricSet ;
2628import org .apache .iotdb .metrics .utils .MetricLevel ;
2729import org .apache .iotdb .metrics .utils .MetricType ;
2830import org .apache .iotdb .metrics .utils .SystemMetric ;
2931
32+ import com .sun .jna .Library ;
33+ import com .sun .jna .Native ;
34+ import com .sun .jna .Structure ;
35+ import com .sun .jna .platform .win32 .BaseTSD .SIZE_T ;
36+ import com .sun .jna .platform .win32 .Kernel32 ;
37+ import com .sun .jna .platform .win32 .WinNT ;
3038import com .sun .management .OperatingSystemMXBean ;
39+ import org .slf4j .Logger ;
40+ import org .slf4j .LoggerFactory ;
3141
42+ import java .io .BufferedReader ;
43+ import java .io .IOException ;
44+ import java .io .InputStreamReader ;
3245import java .lang .management .ManagementFactory ;
46+ import java .nio .file .Files ;
47+ import java .nio .file .Path ;
48+ import java .nio .file .Paths ;
3349
3450public class ProcessMetrics implements IMetricSet {
51+ private static final Logger LOGGER = LoggerFactory .getLogger (ProcessMetrics .class );
52+ private static final MetricConfig CONFIG = MetricConfigDescriptor .getInstance ().getMetricConfig ();
3553 private final OperatingSystemMXBean sunOsMxBean ;
3654 private final Runtime runtime ;
3755 private static final String PROCESS = "process" ;
56+ private static final String LINUX_RSS_PREFIX = "VmRSS:" ;
3857 private long lastUpdateTime = 0L ;
3958 private volatile long processCpuLoad = 0L ;
4059 private volatile long processCpuTime = 0L ;
@@ -213,7 +232,68 @@ private void removeProcessStatusInfo(AbstractMetricService metricService) {
213232 }
214233
215234 private long getProcessUsedMemory () {
216- return runtime .totalMemory () - runtime .freeMemory ();
235+ long residentMemory = getResidentMemory ();
236+ return residentMemory > 0 ? residentMemory : runtime .totalMemory () - runtime .freeMemory ();
237+ }
238+
239+ private long getResidentMemory () {
240+ if (CONFIG .getPid ().isEmpty ()) {
241+ return 0L ;
242+ }
243+ try {
244+ switch (CONFIG .getSystemType ()) {
245+ case LINUX :
246+ return getLinuxResidentMemory ();
247+ case MAC :
248+ return getMacResidentMemory ();
249+ case WINDOWS :
250+ return getWindowsResidentMemory ();
251+ default :
252+ return 0L ;
253+ }
254+ } catch (Exception e ) {
255+ LOGGER .debug ("Failed to get process resident memory for pid {}" , CONFIG .getPid (), e );
256+ return 0L ;
257+ }
258+ }
259+
260+ private long getLinuxResidentMemory () throws IOException {
261+ Path statusPath = Paths .get (String .format ("/proc/%s/status" , CONFIG .getPid ()));
262+ if (!Files .exists (statusPath )) {
263+ return 0L ;
264+ }
265+ for (String line : Files .readAllLines (statusPath )) {
266+ if (line .startsWith (LINUX_RSS_PREFIX )) {
267+ String [] parts = line .trim ().split ("\\ s+" );
268+ if (parts .length >= 2 ) {
269+ return Long .parseLong (parts [1 ]) * 1024L ;
270+ }
271+ }
272+ }
273+ return 0L ;
274+ }
275+
276+ private long getMacResidentMemory () throws IOException , InterruptedException {
277+ Process process = runtime .exec (new String [] {"ps" , "-o" , "rss=" , "-p" , CONFIG .getPid ()});
278+ try (BufferedReader input =
279+ new BufferedReader (new InputStreamReader (process .getInputStream ()))) {
280+ String line = input .readLine ();
281+ int exitCode = process .waitFor ();
282+ if (exitCode == 0 && line != null && !line .trim ().isEmpty ()) {
283+ return Long .parseLong (line .trim ()) * 1024L ;
284+ }
285+ }
286+ return 0L ;
287+ }
288+
289+ private long getWindowsResidentMemory () {
290+ WinNT .HANDLE hProcess = Kernel32 .INSTANCE .GetCurrentProcess ();
291+ ProcessMemoryCounters counters = new ProcessMemoryCounters ();
292+ boolean success = PsapiExt .INSTANCE .GetProcessMemoryInfo (hProcess , counters , counters .size ());
293+ if (!success ) {
294+ return 0L ;
295+ }
296+ return counters .workingSetSize .longValue ();
217297 }
218298
219299 private long getProcessStatus () {
@@ -233,4 +313,35 @@ private double getProcessMemoryRatio() {
233313 long totalPhysicalMemorySize = sunOsMxBean .getTotalPhysicalMemorySize ();
234314 return (double ) processUsedMemory / (double ) totalPhysicalMemorySize * 100 ;
235315 }
316+
317+ public interface PsapiExt extends Library {
318+ PsapiExt INSTANCE = Native .load ("psapi" , PsapiExt .class );
319+
320+ boolean GetProcessMemoryInfo (WinNT .HANDLE process , ProcessMemoryCounters counters , int size );
321+ }
322+
323+ @ Structure .FieldOrder ({
324+ "cb" ,
325+ "pageFaultCount" ,
326+ "peakWorkingSetSize" ,
327+ "workingSetSize" ,
328+ "quotaPeakPagedPoolUsage" ,
329+ "quotaPagedPoolUsage" ,
330+ "quotaPeakNonPagedPoolUsage" ,
331+ "quotaNonPagedPoolUsage" ,
332+ "pagefileUsage" ,
333+ "peakPagefileUsage"
334+ })
335+ public static class ProcessMemoryCounters extends Structure {
336+ public int cb = size ();
337+ public int pageFaultCount ;
338+ public SIZE_T peakWorkingSetSize ;
339+ public SIZE_T workingSetSize ;
340+ public SIZE_T quotaPeakPagedPoolUsage ;
341+ public SIZE_T quotaPagedPoolUsage ;
342+ public SIZE_T quotaPeakNonPagedPoolUsage ;
343+ public SIZE_T quotaNonPagedPoolUsage ;
344+ public SIZE_T pagefileUsage ;
345+ public SIZE_T peakPagefileUsage ;
346+ }
236347}
0 commit comments