package ij.plugin; import ij.*; import ij.gui.*; import java.io.*; import ij.util.Tools; /** This plugin implements the Edit/Options/Memory command. */ public class Memory implements PlugIn { String s; int index1, index2; File f; boolean fileMissing; boolean sixtyFourBit; public void run(String arg) { changeMemoryAllocation(); //IJ.log("setting="+getMemorySetting()/(1024*1024)+"MB"); //IJ.log("maxMemory="+maxMemory()/(1024*1024)+"MB"); } void changeMemoryAllocation() { IJ.maxMemory(); // forces IJ to cache old limit int max = (int)(getMemorySetting()/1048576L); boolean unableToSet = max==0; if (max==0) max = (int)(maxMemory()/1048576L); String title = "Memory "+(IJ.is64Bit()?"(64-bit)":"(32-bit)"); GenericDialog gd = new GenericDialog(title); gd.addNumericField("Maximum memory:", max, 0, 5, "MB"); gd.addNumericField("Parallel threads for stacks:", Prefs.getThreads(), 0, 5, ""); gd.setInsets(12, 0, 0); gd.addCheckbox("Keep multiple undo buffers", Prefs.keepUndoBuffers); gd.setInsets(12, 0, 0); gd.addCheckbox("Run garbage collector on status bar click", !Prefs.noClickToGC); gd.addHelp(IJ.URL+"/docs/menus/edit.html#memory"); gd.showDialog(); if (gd.wasCanceled()) return; int max2 = (int)gd.getNextNumber(); Prefs.setThreads((int)gd.getNextNumber()); Prefs.keepUndoBuffers = gd.getNextBoolean(); Prefs.noClickToGC = !gd.getNextBoolean(); if (gd.invalidNumber()) { IJ.showMessage("Memory", "The number entered was invalid."); return; } if (unableToSet && max2!=max) {showError(); return;} if (max2<256 && IJ.isMacOSX()) max2 = 256; if (max2<32 && IJ.isWindows()) max2 = 32; if (max2==max) return; int limit = IJ.isWindows()?1600:1700; String OSXInfo = ""; if (IJ.isMacOSX()) OSXInfo = "\n \nOn Max OS X, use\n" +"/Applications/Utilities/Java/Java Preferences\n" +"to switch to a 64-bit version of Java. You may\n" +"also need to run \"ImageJ64\" instead of \"ImageJ\"."; if (max2>=limit && !IJ.is64Bit()) { if (!IJ.showMessageWithCancel(title, "Note: setting the memory limit to a value\n" +"greater than "+limit+"MB on a 32-bit system\n" +"may cause ImageJ to fail to start. The title of\n" +"the Edit>Options>Memory & Threads dialog\n" +"box changes to \"Memory (64-bit)\" when ImageJ\n" +"is running on a 64-bit version of Java." + OSXInfo)); return; } try { String s2 = s.substring(index2); if (s2.startsWith("g")) s2 = "m"+s2.substring(1); String s3 = s.substring(0, index1) + max2 + s2; FileOutputStream fos = new FileOutputStream(f); PrintWriter pw = new PrintWriter(fos); pw.print(s3); pw.close(); } catch (IOException e) { String error = e.getMessage(); if (error==null || error.equals("")) error = ""+e; String name = IJ.isMacOSX()?"Info.plist":"ImageJ.cfg"; String msg = "Unable to update the file \"" + name + "\".\n" + " \n" + "\"" + error + "\""; if (IJ.isVista()) msg += Prefs.vistaHint; IJ.showMessage("Memory", msg); return; } String hint = ""; if (IJ.isWindows() && max2>640 && max2>max) hint = "\nDelete the \"ImageJ.cfg\" file, located in the ImageJ folder,\nif ImageJ fails to start."; IJ.showMessage("Memory", "The new " + max2 +"MB limit will take effect after ImageJ is restarted."+hint); } public long getMemorySetting() { if (IJ.getApplet()!=null) return 0L; long max = 0L; if (IJ.isMacOSX()) { if (IJ.is64Bit()) max = getMemorySetting("ImageJ64.app/Contents/Info.plist"); if (max==0L) { max = getMemorySetting("ImageJ.app/Contents/Info.plist"); } } else max = getMemorySetting("ImageJ.cfg"); return max; } void showError() { int max = (int)(maxMemory()/1048576L); String msg = "ImageJ is unable to change the memory limit. For \n" + "more information, refer to the installation notes at\n \n" + " "+IJ.URL+"/docs/install/\n" + " \n"; if (fileMissing) { if (IJ.isMacOSX()) msg += "The ImageJ application (ImageJ.app) was not found.\n \n"; else if (IJ.isWindows()) msg += "ImageJ.cfg not found.\n \n"; fileMissing = false; } if (max>0) msg += "Current limit: " + max + "MB"; if (IJ.isVista()) msg += Prefs.vistaHint; IJ.showMessage("Memory", msg); } long getMemorySetting(String file) { String path = Prefs.getHomeDir()+File.separator+file; f = new File(path); if (!f.exists()) { fileMissing = true; return 0L; } long max = 0L; try { int size = (int)f.length(); byte[] buffer = new byte[size]; FileInputStream in = new FileInputStream(f); in.read(buffer, 0, size); s = new String(buffer, 0, size, "ISO8859_1"); in.close(); index1 = s.indexOf("-mx"); if (index1==-1) index1 = s.indexOf("-Xmx"); if (index1==-1) return 0L; if (s.charAt(index1+1)=='X') index1+=4; else index1+=3; index2 = index1; while (index2<s.length()-1 && Character.isDigit(s.charAt(++index2))) {} String s2 = s.substring(index1, index2); max = (long)Tools.parseDouble(s2, 0.0)*1024*1024; if (index2<s.length() && s.charAt(index2)=='g') max = max*1024L; } catch (Exception e) { IJ.log(""+e); return 0L; } return max; } /** Returns the maximum amount of memory this JVM will attempt to use. */ public long maxMemory() { return Runtime.getRuntime().maxMemory(); } }