001/* 002 * This file is part of McIDAS-V 003 * 004 * Copyright 2007-2024 005 * Space Science and Engineering Center (SSEC) 006 * University of Wisconsin - Madison 007 * 1225 W. Dayton Street, Madison, WI 53706, USA 008 * https://www.ssec.wisc.edu/mcidas/ 009 * 010 * All Rights Reserved 011 * 012 * McIDAS-V is built on Unidata's IDV and SSEC's VisAD libraries, and 013 * some McIDAS-V source code is based on IDV and VisAD source code. 014 * 015 * McIDAS-V is free software; you can redistribute it and/or modify 016 * it under the terms of the GNU Lesser Public License as published by 017 * the Free Software Foundation; either version 3 of the License, or 018 * (at your option) any later version. 019 * 020 * McIDAS-V is distributed in the hope that it will be useful, 021 * but WITHOUT ANY WARRANTY; without even the implied warranty of 022 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 023 * GNU Lesser Public License for more details. 024 * 025 * You should have received a copy of the GNU Lesser Public License 026 * along with this program. If not, see https://www.gnu.org/licenses/. 027 */ 028package edu.wisc.ssec.mcidasv.monitors.memory; 029 030import java.awt.Color; 031import java.text.DecimalFormat; 032import java.util.List; 033import java.util.concurrent.CopyOnWriteArrayList; 034 035import javax.swing.SwingUtilities; 036 037import ucar.unidata.util.Msg; 038 039import edu.wisc.ssec.mcidasv.monitors.MonitorManager; 040import edu.wisc.ssec.mcidasv.monitors.Monitorable; 041import edu.wisc.ssec.mcidasv.monitors.Monitoring; 042 043public class MemoryMonitor implements Monitorable { 044 045 private final DecimalFormat fmt = new DecimalFormat("#0"); 046 047 private final MonitorManager manager; 048 049 private final int percentThreshold; 050 051 private final int percentCancel; 052 053 private int timesAboveThreshold; 054 055 private long lastTimeRanGC = -1; 056 057 private final List<Monitoring> listeners = new CopyOnWriteArrayList<>(); 058 059 public MemoryMonitor(final MonitorManager manager, final int threshold, final int cancel) { 060 this.manager = manager; 061 percentThreshold = threshold; 062 percentCancel = cancel; 063 } 064 065 public void addMonitor(final Monitoring listener) { 066 listeners.add(listener); 067 } 068 069 public void removeMonitor(final Monitoring listener) { 070 if (!listeners.isEmpty()) { 071 listeners.remove(listener); 072 } 073 } 074 075 public boolean hasMonitors() { 076 return !listeners.isEmpty(); 077 } 078 079 public void run() { 080 double totalMem = Runtime.getRuntime().maxMemory(); 081 double highMem = Runtime.getRuntime().totalMemory(); 082 double freeMem = Runtime.getRuntime().freeMemory(); 083 double usedMem = (highMem - freeMem); 084 085 totalMem = totalMem / 1048576; 086 usedMem = usedMem / 1048576; 087 highMem = highMem / 1048576; 088 089 int percent = (int)(100.0f * (usedMem / totalMem)); 090 int stretchedPercent = 0; 091 092 long now = System.currentTimeMillis(); 093 if (lastTimeRanGC < 0) { 094 lastTimeRanGC = now; 095 } 096 097 if (percent > percentThreshold) { 098 timesAboveThreshold++; 099 if (timesAboveThreshold > 5) { 100 if (now - lastTimeRanGC > 5000) { 101 manager.scheduleClearCache(); 102 lastTimeRanGC = now; 103 } 104 } 105 stretchedPercent = Math.round((percent - percentThreshold) * (100.0f / (100.0f - percentThreshold))); 106 } else { 107 timesAboveThreshold = 0; 108 lastTimeRanGC = now; 109 } 110 111 String output = " " + Msg.msg("Memory:") + " " + 112 fmt.format(usedMem) + "/" + 113 fmt.format(highMem) + "/" + 114 fmt.format(totalMem) + " " + Msg.msg("MB"); 115 final MemoryMonitorEvent event = new MemoryMonitorEvent(this, doColorThing(stretchedPercent), output); 116 for (final Monitoring listener : listeners) { 117 SwingUtilities.invokeLater(new Runnable() { 118 public void run() { 119 listener.monitorUpdated(event); 120 } 121 }); 122 } 123 } 124 125 public static Color doColorThing(final int percent) { 126 Float alpha = new Float(percent).floatValue() / 100; 127 return new Color(1.0f, 0.0f, 0.0f, alpha); 128 } 129}