Skip to content

Commit

Permalink
merge 0.8 branch
Browse files Browse the repository at this point in the history
  • Loading branch information
henderea committed Jul 27, 2014
1 parent 8e0ca95 commit 4f3437f
Show file tree
Hide file tree
Showing 12 changed files with 199 additions and 46 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:** <http://memorytamer.s3.amazonaws.com/MemoryTamer-0.3.zip> (Mavericks-only)
Expand All @@ -46,3 +47,4 @@ A RubyMotion application for keeping memory usage in check. Shows up in the men
* **v0.7.6:** <https://memorytamer.s3.amazonaws.com/MemoryTamer-0.7.6.zip>
* **v0.7.7:** <https://memorytamer.s3.amazonaws.com/MemoryTamer-0.7.7.zip>
* **v0.7.8:** <https://memorytamer.s3.amazonaws.com/MemoryTamer-0.7.8.zip>
* **v0.8:** <https://memorytamer.s3.amazonaws.com/MemoryTamer-0.8.zip>
4 changes: 2 additions & 2 deletions Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down
13 changes: 9 additions & 4 deletions USING.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand All @@ -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

Expand Down
119 changes: 82 additions & 37 deletions app/app_delegate.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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?
Expand All @@ -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)
Expand All @@ -193,19 +192,30 @@ 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
unit = %w(B KB MB GB TB)[lg]
"#{'%.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)
Expand All @@ -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}"
Expand All @@ -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
Expand All @@ -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
Expand Down
8 changes: 5 additions & 3 deletions app/menu.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down Expand Up @@ -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
___
Expand Down
9 changes: 9 additions & 0 deletions appcast.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,15 @@
<link>https://raw.githubusercontent.com/henderea/MemoryTamer/master/appcast.xml</link>
<description>Most recent changes with links to updates.</description>
<language>en</language>
<item>
<title>Version 0.8</title>
<sparkle:releaseNotesLink>
http://releases.io/henderea/MemoryTamer/0.8?heading=true
</sparkle:releaseNotesLink>
<pubDate>Sun, 27 Jul 2014 11:15:00 -0400</pubDate>
<enclosure url="http://memorytamer.s3.amazonaws.com/MemoryTamer-0.8.zip" sparkle:version="0.8" length="4563455" type="application/octet-stream" />
<sparkle:minimumSystemVersion>10.7</sparkle:minimumSystemVersion>
</item>
<item>
<title>Version 0.7.8</title>
<sparkle:releaseNotesLink>
Expand Down
File renamed without changes.
Binary file added files/Prefs.nib
Binary file not shown.
Loading

0 comments on commit 4f3437f

Please sign in to comment.