From 4f3437f28af9ddaf299bc2ac606fce4c7667b84a Mon Sep 17 00:00:00 2001 From: Eric Henderson Date: Sun, 27 Jul 2014 11:37:32 -0400 Subject: [PATCH] merge 0.8 branch --- README.md | 2 + Rakefile | 4 +- USING.md | 13 +- app/app_delegate.rb | 119 ++++++++++++------ app/menu.rb | 8 +- appcast.xml | 9 ++ Icon.psd => files/Icon.psd | Bin files/Prefs.nib | Bin 0 -> 10719 bytes files/Prefs.xib | 83 ++++++++++++ .../newMemoryTamerIcon.ai | 0 .../newMemoryTamerIcon2.ai | 0 files/prefs.rb | 7 ++ 12 files changed, 199 insertions(+), 46 deletions(-) rename Icon.psd => files/Icon.psd (100%) create mode 100644 files/Prefs.nib create mode 100644 files/Prefs.xib rename newMemoryTamerIcon.ai => files/newMemoryTamerIcon.ai (100%) rename newMemoryTamerIcon2.ai => files/newMemoryTamerIcon2.ai (100%) create mode 100644 files/prefs.rb diff --git a/README.md b/README.md index 234c017..450e0d8 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,7 @@ A RubyMotion application for keeping memory usage in check. Shows up in the men * **v0.7.6:** update icon * **v0.7.7:** add "Using MemoryTamer" to the Support menu * **v0.7.8:** add retina status icon +* **v0.8:** add memory quick-trimming functionality and remove the old "reload preferences" menu item ###Versions (code-signed with developer ID): * **v0.3:** (Mavericks-only) @@ -46,3 +47,4 @@ A RubyMotion application for keeping memory usage in check. Shows up in the men * **v0.7.6:** * **v0.7.7:** * **v0.7.8:** +* **v0.8:** diff --git a/Rakefile b/Rakefile index 1bfaf47..5ae4d47 100644 --- a/Rakefile +++ b/Rakefile @@ -27,8 +27,8 @@ Motion::Project::App.setup do |app| app.icon = 'Icon.icns' app.info_plist['CFBundleIconFile'] = 'Icon.icns' app.name = 'MemoryTamer' - app.version = '0.7.8' - app.short_version = '0.7.8' + app.version = '0.8' + app.short_version = '0.8' app.identifier = 'us.myepg.MemoryTamer' app.info_plist['NSUIElement'] = 1 app.info_plist['SUFeedURL'] = 'https://raw.githubusercontent.com/henderea/MemoryTamer/master/appcast.xml' diff --git a/USING.md b/USING.md index e0c8ed4..0a6f88a 100644 --- a/USING.md +++ b/USING.md @@ -4,10 +4,8 @@ ##Explanation of Preferences -**NOTE:** "Reload Preferences" will attempt to reload settings from the preferences storage. This will not normally be of any use because preferences are loaded on startup and the preferences storage is updated with each preference change. - ###Notifications -This option is the pair of menu items that appear directly below the "Reload Preferences" item. It controls which notification system you are using. +This option is the pair of menu items that appear at the top of the Preferences menu. It controls which notification system you are using. If you are on OS X 10.7 Lion, it will be set to Growl and not allow changing. If you are on OS X 10.8 Mountain Lion or above, it will default to Notification Center with the option to switch to Growl. @@ -27,8 +25,15 @@ The memory threshold can be hard to get right. I would suggest that you try fre Another tip is to pay attention to how quickly the free memory drops after you free it up. It would probably be a good idea to avoid using a threshold that it gets back down to quickly. +###Memory Trim Threshold +Version 0.8 introduced Memory Trimming. The settings for this have been placed directly under Memory Threshold. This setting controls at what amount of free memory MemoryTamer will do a quick "trim" of the memory. + +This uses the plain allocation method (see Freeing Method) tool, but will also run when the method is set to memory pressure. This will not try to free up as much memory as a full freeing, but it should be faster than a typical freeing and should cause less slowness than a full plain allocation freeing. + +The default value for this setting is 0 (disabled), but if you do use it, you should set the value above your full memory freeing threshold. A suggestion might be to make it 1.5 or 2 times the amount, but it will probably take some experimentation to figure a good value out. + ###Freeing Pressure -This option is the next pair of items in the Preferences menu, after Memory Threshold. It controls how aggressive it will be when freeing. +This option is the next pair of items in the Preferences menu, after Memory Trim Threshold. It controls how aggressive it will be when freeing. **NOTE:** this option is only available on OS X 10.9 Mavericks and up, and only applies to the "memory pressure" freeing method diff --git a/app/app_delegate.rb b/app/app_delegate.rb index c2694b9..e59dd36 100644 --- a/app/app_delegate.rb +++ b/app/app_delegate.rb @@ -37,35 +37,22 @@ def applicationDidFinishLaunching(notification) MainMenu[:license].subscribe(:license_change) { |_, _| Paddle.sharedInstance.showLicencing } - MainMenu[:prefs].subscribe(:preferences_refresh) { |_, _| - NSLog 'Reloading preferences' - load_prefs - set_all_displays - } MainMenu[:prefs].subscribe(:notification_change) { |_, _| App::Persistence['growl'] = !App::Persistence['growl'] set_notification_display }.canExecuteBlock { |_| @has_nc } MainMenu[:prefs].subscribe(:memory_change) { |_, _| - nm = get_input("Please enter the memory threshold in MB (0 - #{get_total_memory / 1024**2})", "#{App::Persistence['mem']}") { |str| (str =~ /^\d*$/) } - if nm - begin - nmi = nm.to_i - if nmi < 0 - alert('The memory threshold must be non-negative!') - elsif nmi > get_total_memory / 1024**2 - alert('You can\'t specify a value above your total ram') - else - App::Persistence['mem'] = nmi - set_mem_display - end - rescue - alert('The memory threshold must be an integer!') - end - end + nm = get_input('Please enter the memory threshold in MB', "#{App::Persistence['mem']}", :int, min: 0, max: (get_total_memory / 1024**2)) + App::Persistence['mem'] = nm if nm + set_mem_display + } + MainMenu[:prefs].subscribe(:trim_change) { |_, _| + nm = get_input('Please enter the memory trim threshold in MB', "#{App::Persistence['trim_mem']}", :int, min: 0, max: (get_total_memory / 1024**2)) + App::Persistence['trim_mem'] = nm if nm + set_trim_display } MainMenu[:prefs].subscribe(:pressure_change) { |_, _| - np = get_input('Please select the freeing pressure', App::Persistence['pressure'], :select, %w(normal warn critical)) + np = get_input('Please select the freeing pressure', App::Persistence['pressure'], :select, values: %w(normal warn critical)) if np if %w(normal warn critical).include?(np) App::Persistence['pressure'] = np @@ -109,6 +96,8 @@ def applicationDidFinishLaunching(notification) @statusItem.setTitle(App::Persistence['show_mem'] ? format_bytes(cfm) : '') if App::Persistence['update_while'] || !@freeing if cfm <= dfm && (NSDate.date - @last_free) >= 60 && !@freeing Thread.start { free_mem_default(cfm) } + elsif cfm <= dtm && (NSDate.date - @last_free) >= 60 && !@freeing + Thread.start { trim_mem(cfm) } end sleep(2) end @@ -118,6 +107,7 @@ def applicationDidFinishLaunching(notification) def set_all_displays set_notification_display set_mem_display + set_trim_display set_pressure_display set_method_display set_escalate_display @@ -133,6 +123,10 @@ def set_notification_display def set_mem_display MainMenu[:prefs].items[:memory_display][:title] = "Memory threshold: #{App::Persistence['mem']} MB" + end + + def set_trim_display + MainMenu[:prefs].items[:trim_display][:title] = "Memory trim threshold: #{App::Persistence['trim_mem']} MB" end def set_pressure_display @@ -147,7 +141,7 @@ def set_method_display def set_escalate_display MainMenu[:prefs].items[:escalate_display][:state] = App::Persistence['auto_escalate'] ? NSOnState : NSOffState - end + end def set_show_display MainMenu[:prefs].items[:show_display][:state] = App::Persistence['show_mem'] ? NSOnState : NSOffState @@ -168,6 +162,7 @@ def set_license_display(note = nil) def load_prefs App::Persistence['mem'] = 1024 if App::Persistence['mem'].nil? + App::Persistence['trim_mem'] = 0 if App::Persistence['trim_mem'].nil? App::Persistence['pressure'] = 'warn' if App::Persistence['pressure'].nil? App::Persistence['growl'] = false if App::Persistence['growl'].nil? App::Persistence['method_pressure'] = true if App::Persistence['method_pressure'].nil? @@ -180,6 +175,10 @@ def load_prefs def dfm App::Persistence['mem'] * 1024**2 + end + + def dtm + App::Persistence['trim_mem'] * 1024**2 end def free_mem_default(cfm) @@ -193,6 +192,17 @@ def free_mem_default(cfm) @last_free = NSDate.date end + def trim_mem(cfm) + @freeing = true + notify 'Beginning memory trimming', 'Start Freeing' + free_mem_old(0.5) + nfm = get_free_mem + notify "Finished trimming #{format_bytes(nfm - cfm)}", 'Finish Freeing' + NSLog "Freed #{format_bytes(nfm - cfm, true)}" + @freeing = false + @last_free = NSDate.date - 30 + end + def format_bytes(bytes, show_raw = false) return "#{bytes} B" if bytes <= 1 lg = (Math.log(bytes)/Math.log(1024)).floor.to_f @@ -200,12 +210,12 @@ def format_bytes(bytes, show_raw = false) "#{'%.2f' % (bytes.to_f / 1024.0**lg)} #{unit}#{show_raw ? " (#{bytes} B)" : ''}" end - def get_free_mem(include_inactive = false) + def get_free_mem(inactive_multiplier = 0) page_size = WeakRef.new(`vm_stat | grep 'page size' | awk '{ print $8 }'`).chomp!.to_i pages_free = WeakRef.new(`vm_stat | grep 'Pages free' | awk '{ print $3 }'`).chomp![0...-1].to_i pages_inactive = WeakRef.new(`vm_stat | grep 'Pages inactive' | awk '{ print $3 }'`).chomp![0...-1].to_i - page_size*pages_free + (include_inactive ? page_size*pages_inactive : 0) + page_size*pages_free + page_size*pages_inactive*inactive_multiplier end def sysctl_get(name) @@ -227,7 +237,7 @@ def free_mem(pressure) notify 'Memory Pressure too high! Running not a good idea.', 'Error' return end - dmp = pressure == 'normal' ? 1 : (pressure == 'warn' ? 2 : 4) + dmp = pressure == 'normal' ? 1 : (pressure == 'warn' ? 2 : 4) if cmp >= dmp && App::Persistence['auto_escalate'] np = cmp == 1 ? 'warn' : 'critical' NSLog "escalating freeing pressure from #{pressure} to #{np}" @@ -249,28 +259,40 @@ def free_mem(pressure) end end - def free_mem_old - mtf = get_free_mem(true) + def free_mem_old(inactive_multiplier = 1) + mtf = get_free_mem(inactive_multiplier) NSLog "#{mtf}" ep = NSBundle.mainBundle.pathForResource('inactive', ofType: '') op = `'#{ep}' '#{mtf}'` NSLog op end - def get_input(message, default_value, type = :text, options = []) - alert = NSAlert.alertWithMessageText(message, defaultButton: 'OK', alternateButton: 'Cancel', otherButton: nil, informativeTextWithFormat: '') + def make_range(min, max) + if min && max + " (#{min}-#{max})" + elsif min + " (min #{min})" + elsif max + " (max #{max})" + else + '' + end + end + + def get_input(message, default_value, type = :text, options = {}) + alert = NSAlert.alertWithMessageText(type == :int ? "#{message}#{make_range(options[:min], options[:max])}" : message, defaultButton: 'OK', alternateButton: 'Cancel', otherButton: nil, informativeTextWithFormat: '') case type when :select - input = NSComboBox.alloc.initWithFrame(NSMakeRect(0, 0, 200, 24)) - input.addItemsWithObjectValues(options) - input.selectItemWithObjectValue(default_value) - when :number + input = NSPopUpButton.alloc.initWithFrame(NSMakeRect(0, 0, 200, 24)) + input.addItemsWithTitles(options[:values]) + input.selectItemWithTitle(default_value) + when :int input = NSTextField.alloc.initWithFrame(NSMakeRect(0, 0, 200, 24)) input.stringValue = "#{default_value}" formatter = NSNumberFormatter.alloc.init formatter.allowsFloats = false - formatter.minimum = 0 - formatter.maximum = get_total_memory / 1024**2 + formatter.minimum = options[:min] + formatter.maximum = options[:max] else input = NSTextField.alloc.initWithFrame(NSMakeRect(0, 0, 200, 24)) input.stringValue = default_value @@ -281,7 +303,30 @@ def get_input(message, default_value, type = :text, options = []) input.validateEditing case type when :select - input.objectValueOfSelectedItem + v = input.titleOfSelectedItem + if options[:values].include?(v) + v + else + alert("Invalid option #{v}!") + nil + end + when :int + v = input.stringValue + begin + vi = v.to_i + if options[:min] && vi < options[:min] + alert("Value must be >= #{options[:min]}") + nil + elsif vi > options[:max] + alert("Value must be < #{options[:max]}") + nil + else + vi + end + rescue + alert('Value must be an integer!') + nil + end else input.stringValue end diff --git a/app/menu.rb b/app/menu.rb index 6f99cf1..27a9eb9 100644 --- a/app/menu.rb +++ b/app/menu.rb @@ -14,11 +14,12 @@ def self.def_items menuItem :status_quit, 'Quit', preset: :quit menuItem :status_preferences, 'Preferences', submenu: :prefs - menuItem :preferences_refresh, 'Reload preferences' menuItem :notification_display, 'Currently using: Growl' menuItem :notification_change, 'Use Notification Center' menuItem :memory_display, 'Memory threshold: 1024 MB' menuItem :memory_change, 'Change memory threshold' + menuItem :trim_display, 'Memory trim threshold: 2048 MB' + menuItem :trim_change, 'Change memory trim threshold' menuItem :pressure_display, 'Freeing pressure: warn' menuItem :pressure_change, 'Change freeing pressure' menuItem :method_display, 'Freeing method: memory pressure' @@ -62,14 +63,15 @@ def self.def_menus } menu(:prefs, 'Preferences') { - preferences_refresh - ___ notification_display notification_change ___ memory_display memory_change ___ + trim_display + trim_change + ___ pressure_display pressure_change ___ diff --git a/appcast.xml b/appcast.xml index b4e004d..8ef392c 100755 --- a/appcast.xml +++ b/appcast.xml @@ -5,6 +5,15 @@ https://raw.githubusercontent.com/henderea/MemoryTamer/master/appcast.xml Most recent changes with links to updates. en + + Version 0.8 + + http://releases.io/henderea/MemoryTamer/0.8?heading=true + + Sun, 27 Jul 2014 11:15:00 -0400 + + 10.7 + Version 0.7.8 diff --git a/Icon.psd b/files/Icon.psd similarity index 100% rename from Icon.psd rename to files/Icon.psd diff --git a/files/Prefs.nib b/files/Prefs.nib new file mode 100644 index 0000000000000000000000000000000000000000..d431d5039ea14505ac8abfe2f9af3cf1d3a70430 GIT binary patch literal 10719 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 B$Lat8 literal 0 HcmV?d00001 diff --git a/files/Prefs.xib b/files/Prefs.xib new file mode 100644 index 0000000..877f74c --- /dev/null +++ b/files/Prefs.xib @@ -0,0 +1,83 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/newMemoryTamerIcon.ai b/files/newMemoryTamerIcon.ai similarity index 100% rename from newMemoryTamerIcon.ai rename to files/newMemoryTamerIcon.ai diff --git a/newMemoryTamerIcon2.ai b/files/newMemoryTamerIcon2.ai similarity index 100% rename from newMemoryTamerIcon2.ai rename to files/newMemoryTamerIcon2.ai diff --git a/files/prefs.rb b/files/prefs.rb new file mode 100644 index 0000000..aabe637 --- /dev/null +++ b/files/prefs.rb @@ -0,0 +1,7 @@ +class Prefs < NSWindowController + extend IB + + outlet :notifications, NSPopUpButton + outlet :notifications_nc, NSMenuItem + +end \ No newline at end of file