/* * Copyright 2004 - 2008 Christian Sprajc. All rights reserved. * * This file is part of PowerFolder. * * PowerFolder is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation. * * PowerFolder is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with PowerFolder. If not, see <http://www.gnu.org/licenses/>. * * $Id$ */ package de.dal33t.powerfolder.util; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; import java.util.logging.Level; import java.util.logging.Logger; import de.dal33t.powerfolder.Controller; import de.dal33t.powerfolder.ui.WikiLinks; import de.dal33t.powerfolder.ui.dialog.DialogFactory; import de.dal33t.powerfolder.ui.dialog.GenericDialogType; import de.dal33t.powerfolder.ui.notices.RunnableNotice; import de.dal33t.powerfolder.ui.notices.NoticeSeverity; import de.dal33t.powerfolder.util.os.OSUtil; import de.dal33t.powerfolder.ui.util.Help; /** * Detects if PowerFolder is running out of memory. */ public class MemoryMonitor implements Runnable { private static final Logger log = Logger.getLogger(MemoryMonitor.class .getName()); private Controller controller; private boolean runAlready; public MemoryMonitor(Controller controller) { this.controller = controller; } public void run() { // Do not show dialog repeatedly. if (runAlready) { return; } Runtime runtime = Runtime.getRuntime(); long maxMemory = runtime.maxMemory(); long totalMemory = runtime.totalMemory(); log.fine("Max Memory: " + Format.formatBytesShort(maxMemory) + ", Total Memory: " + Format.formatBytesShort(totalMemory)); if (maxMemory == totalMemory) { addWarning(); runAlready = true; } } /** * Add a warning event for the user. */ private void addWarning() { RunnableNotice notice = new RunnableNotice(Translation .getTranslation("warning_notice.title"), Translation .getTranslation("warning_notice.low_memory"), new Runnable() { public void run() { if ((OSUtil.isWindowsSystem() || OSUtil.isMacOS()) && !OSUtil.isWebStart()) { int response = DialogFactory .genericDialog(controller, Translation .getTranslation("low_memory.title"), Translation .getTranslation("low_memory.text", Help .getWikiArticleURL(controller, WikiLinks.MEMORY_CONFIGURATION)), new String[]{ Translation .getTranslation("low_memory.increase"), Translation .getTranslation("low_memory.do_nothing")}, 0, GenericDialogType.WARN); if (response == 0) { // Increase memory increaseAvailableMemory(); } } else { // No ini - Can only warn user. DialogFactory.genericDialog(controller, Translation .getTranslation("low_memory.title"), Translation .getTranslation("low_memory.warn"), new String[]{Translation.getTranslation("general.ok")}, 0, GenericDialogType.WARN); } } }, NoticeSeverity.WARINING); controller.getUIController().getApplicationModel().getNoticesModel() .handleNotice(notice); } /** * Reconfigure ini from (initial) 512M to 1024M max memory. */ private void increaseAvailableMemory() { if (OSUtil.isMacOS()) { increaseAvailableMemoryMac(); } else { increaseAvailableMemoryWin(); } } /** * Reconfigure ini from (initial) 512M to 1024M max memory. */ private void increaseAvailableMemoryWin() { // Read the current ini file. boolean wroteNewIni = false; PrintWriter pw = null; try { // log.fine("Looking for ini..."); // br = new BufferedReader(new FileReader("PowerFolder.ini")); // Loggable.logFineStatic(MemoryMonitor.class, "Found ini..."); // String line; // boolean found = false; // while ((line = br.readLine()) != null) { // if (line.startsWith("-Xmx")) { // // Found default ini. // found = true; // Loggable.logFineStatic(MemoryMonitor.class, // "Found maximum memory line..."); // } // } boolean alreadyMax = Runtime.getRuntime().totalMemory() / 1024 / 1024 > 1023; // Write a new one if found. if (!alreadyMax) { pw = new PrintWriter(new FileWriter(controller.getL4JININame())); log.fine("Writing new ini..."); pw.println("-Xms16m"); pw.println("-Xmx1024m"); pw.println("-XX:MaxPermSize=256m"); pw.println("-XX:MinHeapFreeRatio=10"); pw.println("-XX:MaxHeapFreeRatio=20"); pw.flush(); wroteNewIni = true; log.fine("Wrote new ini..."); } } catch (IOException e) { log.log(Level.FINE, "Problem reconfiguring ini: " + e.getMessage()); } finally { // if (br != null) { // try { // br.close(); // } catch (IOException e) { // // Ignore // } // } if (pw != null) { pw.close(); } } // Show a response if (wroteNewIni) { DialogFactory.genericDialog(controller, Translation .getTranslation("low_memory.title"), Translation .getTranslation("low_memory.configure_success"), GenericDialogType.INFO); } else { DialogFactory.genericDialog(controller, Translation .getTranslation("low_memory.title"), Translation .getTranslation("low_memory.configure_failure"), GenericDialogType.WARN); } } /** * Reconfigure Info.plist from (initial) 512M to 1024M max memory. */ private void increaseAvailableMemoryMac() { boolean success = false; PrintWriter pw = null; BufferedReader br = null; try { log.fine("Looking for Contents/Info.plist..."); File orig = new File(controller.getDistribution().getBinaryName() + ".app/Contents/Info.plist"); log.info("Modifing " + orig.getCanonicalPath()); File temp = new File(controller.getDistribution().getBinaryName() + ".app/Contents/Info.plist.temp"); File back = new File(controller.getDistribution().getBinaryName() + ".app/Contents/Info.plist.backup"); br = new BufferedReader(new FileReader(orig)); pw = new PrintWriter(new FileWriter(temp)); String line; while ((line = br.readLine()) != null) { if (line.trim().startsWith("<string>-Xm") && !line.contains("-Xmx1024m")) { pw .write(" <string>-Xms16m -Xmx1024m -XX:MaxPermSize=256m " + "-XX:MinHeapFreeRatio=5 -XX:MaxHeapFreeRatio=10</string>"); success = true; } else { pw.write(line); } pw.write('\n'); } br.close(); pw.close(); FileUtils.copyFile(orig, back); FileUtils.copyFile(temp, orig); } catch (IOException e) { log.log(Level.WARNING, "Problem reconfiguring Contents/Info.plist: " + e.getMessage(), e); success = false; } finally { if (br != null) { try { br.close(); } catch (IOException e) { // Ignore } } if (pw != null) { pw.close(); } } // Show a response if (success) { DialogFactory.genericDialog(controller, Translation .getTranslation("low_memory.title"), Translation .getTranslation("low_memory.configure_success"), GenericDialogType.INFO); } else { DialogFactory.genericDialog(controller, Translation .getTranslation("low_memory.title"), Translation .getTranslation("low_memory.configure_failure"), GenericDialogType.WARN); } } }