久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

如何提高 Ruby On Rails 性能 – 碼農(nóng)網(wǎng)

 ricosxf 2016-04-15

1 Introduction簡(jiǎn)介

大家總是說(shuō) Rails 好慢啊,這差不多已經(jīng)成為 Ruby and Rails 社區(qū)里的一個(gè)老生常談的問(wèn)題了,。然而實(shí)際上這個(gè)說(shuō)法并不正確,。只要正確使用 Rails,把你的應(yīng)用運(yùn)行速度提升 10 倍并不困難,。那么如何優(yōu)化你的應(yīng)用呢,,我們來(lái)了解下面的內(nèi)容。

1.1 優(yōu)化一個(gè) Rails app 的步驟

導(dǎo)致你的 Rails 應(yīng)用變慢無(wú)非以下兩個(gè)原因:

  1. 在不應(yīng)該將 Ruby and Rails 作為首選的地方使用 Ruby and Rails。(用 Ruby and Rails 做了不擅長(zhǎng)做的工作)
  2. 過(guò)度的消耗內(nèi)存導(dǎo)致需要利用大量的時(shí)間進(jìn)行垃圾回收,。

Rails 是個(gè)令人愉快的框架,,而且 Ruby 也是一個(gè)簡(jiǎn)潔而優(yōu)雅的語(yǔ)言。但是如果它被濫用,,那會(huì)相當(dāng)?shù)挠绊懶阅?。有很多工作并不適合用 Ruby and Rails,你最好使用其它的工具,,比如,,數(shù)據(jù)庫(kù)在大數(shù)據(jù)處理上優(yōu)勢(shì)明顯,R 語(yǔ)言特別適合做統(tǒng)計(jì)學(xué)相關(guān)的工作,。

內(nèi)存問(wèn)題是導(dǎo)致諸多 Ruby 應(yīng)用變慢的首要原因,。Rails 性能優(yōu)化的 80-20 法則是這樣的:80% 的提速是源自于對(duì)內(nèi)存的優(yōu)化,剩下的 20% 屬于其它因素,。為什么內(nèi)存消耗如此重要呢,?因?yàn)槟惴峙涞膬?nèi)存越多,Ruby GC(Ruby 的垃圾回收機(jī)制)需要做的工作也就越多,。Rails 就已經(jīng)占用了很大的內(nèi)存了,,而且平均每個(gè)應(yīng)用剛剛啟動(dòng)后都要占用將近 100M 的內(nèi)存。如果你不注意內(nèi)存的控制,,你的程序內(nèi)存增長(zhǎng)超過(guò) 1G 是很有可能的,。需要回收這么多的內(nèi)存,難怪程序執(zhí)行的大部分時(shí)間都被 GC 占用了,。

2 我們?nèi)绾问挂粋€(gè) Rails 應(yīng)用運(yùn)行更快?

有三種方法可以讓你的應(yīng)用更快:擴(kuò)容,、緩存和代碼優(yōu)化。

擴(kuò)容在如今很容易實(shí)現(xiàn),。Heroku 基本上就是為你做這個(gè)的,,而 Hirefire 則讓這一過(guò)程更加的自動(dòng)化。你可以在這個(gè)了解到更多有關(guān)自動(dòng)擴(kuò)容的內(nèi)容,。其它的托管環(huán)境提供了類(lèi)似的解決方案,。總之,,可以的話(huà)你用它就是了,。但是請(qǐng)牢記擴(kuò)容并不是一顆改善性能的銀彈。如果你的應(yīng)用只需在 5 分鐘內(nèi)響應(yīng)一個(gè)請(qǐng)求,,擴(kuò)容就沒(méi)有什么用,。還有就是用 Heroku + Hirefire 幾乎很容易導(dǎo)致你的銀行賬戶(hù)透支。我已經(jīng)見(jiàn)識(shí)過(guò) Hirefire 把我一個(gè)應(yīng)用的擴(kuò)容至 36 個(gè)實(shí)體,,讓我為此支付了 $3100。我立馬就手動(dòng)吧實(shí)例減容到了 2 個(gè), 并且對(duì)代碼進(jìn)行了優(yōu)化.

Rails 緩存也很容易實(shí)施。Rails 4 中的塊緩存非常不錯(cuò),。Rails 文檔 是有關(guān)緩存知識(shí)的優(yōu)秀資料,。另外還有一篇 Cheyne Wallace 有關(guān) Rails 性能的文章 也值得一讀。如今設(shè)置 Memcached 也簡(jiǎn)單,。不過(guò)同擴(kuò)容相比,,緩存并不能成為性能問(wèn)題的終極解決方案。如果你的代碼無(wú)法理想的運(yùn)行,,那么你將發(fā)現(xiàn)自己會(huì)把越來(lái)越多的資源耗費(fèi)在緩存上,,直到緩存再也不能帶來(lái)速度的提升。

讓你的 Rails 應(yīng)用更快的唯一可靠的方式就是代碼優(yōu)化,。在 Rails 的場(chǎng)景中這就是內(nèi)存優(yōu)化,。而理所當(dāng)然的是,如果你接受了我的建議,,并且避免把 Rails 用于它的設(shè)計(jì)能力范圍之外,,你就會(huì)有更少的代碼要優(yōu)化。

2.1 避免內(nèi)存密集型Rails特性

Rails 一些特性花費(fèi)很多內(nèi)存導(dǎo)致額外的垃圾收集,。列表如下,。

2.1.1 序列化程序

序列化程序是從數(shù)據(jù)庫(kù)讀取的字符串表現(xiàn)為 Ruby 數(shù)據(jù)類(lèi)型的實(shí)用方法。

class Smth < ActiveRecord::Base
  serialize :data, JSON
end
Smth.find(...).data
Smth.find(...).data = { ... }
But convenience comes with 3x memory overhead. If you store 100M in data column, expect to allocate 300M just to read it from the database.

它要消耗更多的內(nèi)存去有效的序列化,,你自己看:

class Smth < ActiveRecord::Base
  def data
    JSON.parse(read_attribute(:data))
  end
  def data=(value)
    write_attribute(:data, value.to_json)
  end
end

這將只要 2 倍的內(nèi)存開(kāi)銷(xiāo),。有些人,包括我自己,,看到 Rails 的 JSON 序列化程序內(nèi)存泄漏,,大約每個(gè)請(qǐng)求 10% 的數(shù)據(jù)量。我不明白這背后的原因,。我也不知道是否有一個(gè)可復(fù)制的情況,。如果你有經(jīng)驗(yàn),或者知道怎么減少內(nèi)存,,請(qǐng)告訴我,。

2.1.2 活動(dòng)記錄

很容易與 ActiveRecord 操縱數(shù)據(jù)。但是 ActiveRecord 本質(zhì)是包裝了你的數(shù)據(jù),。如果你有 1g 的表數(shù)據(jù),,ActiveRecord 表示將要花費(fèi) 2g,在某些情況下更多,。是的,,90% 的情況,你獲得了額外的便利,。但是有的時(shí)候你并不需要,,比如,批量更新可以減少 ActiveRecord 開(kāi)銷(xiāo)。下面的代碼,,即不會(huì)實(shí)例化任何模型,,也不會(huì)運(yùn)行驗(yàn)證和回調(diào)。

Book.where('title LIKE ?', '%Rails%').update_all(author: 'David')

后面的場(chǎng)景它只是執(zhí)行 SQL 更新語(yǔ)句,。

update books
  set author = 'David'
  where title LIKE '%Rails%'
Another example is iteration over a large dataset. Sometimes you need only the data. No typecasting, no updates. This snippet just runs the query and avoids ActiveRecord altogether:
result = ActiveRecord::Base.execute 'select * from books'
result.each do |row|
  # do something with row.values_at('col1', 'col2')
end

2.1.3 字符串回調(diào)

Rails 回調(diào)像之前/之后的保存,,之前/之后的動(dòng)作,以及大量的使用,。但是你寫(xiě)的這種方式可能影響你的性能,。這里有 3 種方式你可以寫(xiě),比如:在保存之前回調(diào):

before_save :update_status
before_save do |model|
model.update_status
end
before_save “self.update_status”

前兩種方式能夠很好的運(yùn)行,,但是第三種不可以,。為什么呢?因?yàn)閳?zhí)行 Rails 回調(diào)需要存儲(chǔ)執(zhí)行上下文(變量,,常量,,全局實(shí)例等等)就是在回調(diào)的時(shí)候。如果你的應(yīng)用很大,,你最終在內(nèi)存里復(fù)制了大量的數(shù)據(jù),。因?yàn)榛卣{(diào)在任何時(shí)候都可以執(zhí)行,內(nèi)存在你程序結(jié)束之前不可以回收,。

有象征,,回調(diào)在每個(gè)請(qǐng)求為我節(jié)省了 0.6 秒。

2.2 寫(xiě)更少的 Ruby

這是我最喜歡的一步,。我的大學(xué)計(jì)算機(jī)科學(xué)類(lèi)教授喜歡說(shuō),,最好的代碼是不存在的。有時(shí)候做好手頭的任務(wù)需要其它的工具,。最常用的是數(shù)據(jù)庫(kù),。為什么呢?因?yàn)?Ruby 不善于處理大數(shù)據(jù)集,。非常非常的糟糕,。記住,Ruby 占用非常大的內(nèi)存,。所以舉個(gè)例子,,處理 1G 的數(shù)據(jù)你可能需要 3G 的或者更多的內(nèi)存。它將要花費(fèi)幾十秒的時(shí)間去垃圾回收這 3G,。好的數(shù)據(jù)庫(kù)可以一秒處理這些數(shù)據(jù),。讓我來(lái)舉一些例子。

2.2.1 屬性預(yù)加載

有時(shí)候反規(guī)范化模型的屬性從另外一個(gè)數(shù)據(jù)庫(kù)獲取,。比如,,想象我們正在構(gòu)建一個(gè) TODO 列表,,包括任務(wù)。每個(gè)任務(wù)可以有一個(gè)或者幾個(gè)標(biāo)簽標(biāo)記,。規(guī)范化數(shù)據(jù)模型是這樣的:

Tasks
 id
 name
Tags
 id
 name
Tasks_Tags
 tag_id
 task_id

加載任務(wù)以及它們的 Rails 標(biāo)簽,,你會(huì)這樣做:

tasks = Task.find(:all, :include => :tags)
    > 0.058 sec

這段代碼有問(wèn)題,它為每個(gè)標(biāo)簽創(chuàng)建了對(duì)象,,花費(fèi)很多內(nèi)存??蛇x擇的解決方案,,將標(biāo)簽在數(shù)據(jù)庫(kù)預(yù)加載。

tasks = Task.select <<-END
      *,
      array(
        select tags.name from tags inner join tasks_tags on (tags.id = tasks_tags.tag_id)
        where tasks_tags.task_id=tasks.id
      ) as tag_names
    END
    > 0.018 sec

這只需要內(nèi)存存儲(chǔ)額外一列,,有一個(gè)數(shù)組標(biāo)簽,。難怪快 3 倍。

2.2.2 數(shù)據(jù)集合

我所說(shuō)的數(shù)據(jù)集合任何代碼去總結(jié)或者分析數(shù)據(jù),。這些操作可以簡(jiǎn)單的總結(jié),,或者一些更復(fù)雜的。以小組排名為例,。假設(shè)我們有一個(gè)員工,,部門(mén),工資的數(shù)據(jù)集,,我們要計(jì)算員工的工資在一個(gè)部門(mén)的排名,。

SELECT * FROM empsalary;
  depname  | empno | salary
-----------+-------+-------
 develop   |     6 |   6000
 develop   |     7 |   4500
 develop   |     5 |   4200
 personnel |     2 |   3900
 personnel |     4 |   3500
 sales     |     1 |   5000
 sales     |     3 |   4800

你可以用 Ruby 計(jì)算排名:

salaries = Empsalary.all
salaries.sort_by! { |s| [s.depname, s.salary] }
key, counter = nil, nil
salaries.each do |s|
 if s.depname != key
  key, counter = s.depname, 0
 end
 counter += 1
 s.rank = counter
end

Empsalary 表里 100K 的數(shù)據(jù)程序在 4.02 秒內(nèi)完成。替代 Postgres 查詢(xún),,使用 window 函數(shù)做同樣的工作在 1.1 秒內(nèi)超過(guò) 4 倍,。

SELECT depname, empno, salary, rank()
OVER (PARTITION BY depname ORDER BY salary DESC)
FROM empsalary;
  depname  | empno | salary | rank 
-----------+-------+--------+------
 develop   |     6 |   6000 |    1
 develop   |     7 |   4500 |    2
 develop   |     5 |   4200 |    3
 personnel |     2 |   3900 |    1
 personnel |     4 |   3500 |    2
 sales     |     1 |   5000 |    1
 sales     |     3 |   4800 |    2

4 倍加速已經(jīng)令人印象深刻,有時(shí)候你得到更多,,到 20 倍,。從我自己經(jīng)驗(yàn)舉個(gè)例子。我有一個(gè)三維 OLAP 多維數(shù)據(jù)集與 600k 數(shù)據(jù)行,。我的程序做了切片和聚合,。在 Ruby 中,它花費(fèi)了 1G 的內(nèi)存大約 90 秒完成,。等價(jià)的 SQL 查詢(xún)?cè)?5 內(nèi)完成,。

2.3 優(yōu)化 Unicorn

如果你正在使用Unicorn,那么以下的優(yōu)化技巧將會(huì)適用,。Unicorn 是 Rails 框架中最快的 web 服務(wù)器,。但是你仍然可以讓它更運(yùn)行得快一點(diǎn)。

2.3.1 預(yù)載入 App 應(yīng)用

Unicorn 可以在創(chuàng)建新的 worker 進(jìn)程前,,預(yù)載入 Rails 應(yīng)用,。這樣有兩個(gè)好處,。第一,主線(xiàn)程可以通過(guò)寫(xiě)入時(shí)復(fù)制的友好GC機(jī)制(Ruby 2.0以上),,共享內(nèi)存的數(shù)據(jù),。操作系統(tǒng)會(huì)透明的復(fù)制這些數(shù)據(jù),以防被worker修改,。第二,,預(yù)載入減少了worker進(jìn)程啟動(dòng)的時(shí)間。Rails worker進(jìn)程重啟是很常見(jiàn)的(稍后將進(jìn)一步闡述),,所以worker重啟的速度越快,,我們就可以得到更好的性能。

若需要開(kāi)啟應(yīng)用的預(yù)載入,,只需要在unicorn的配置文件中添加一行:

preload_app true

2.3.2 在 Request 請(qǐng)求間的 GC

請(qǐng)謹(jǐn)記,,GC 的處理時(shí)間最大會(huì)占到應(yīng)用時(shí)間的50%。這個(gè)還不是唯一的問(wèn)題,。GC 通常是不可預(yù)知的,,并且會(huì)在你不想它運(yùn)行的時(shí)候觸發(fā)運(yùn)行。那么,,你該怎么處理,?

首先我們會(huì)想到,如果完全禁用 GC 會(huì)怎么樣,?這個(gè)似乎是個(gè)很糟糕的想法,。你的應(yīng)用很可能很快就占滿(mǎn) 1G 的內(nèi)存,而你還未能及時(shí)發(fā)現(xiàn),。如果你服務(wù)器還同時(shí)運(yùn)行著幾個(gè) worker,,那么你的應(yīng)用將很快會(huì)出現(xiàn)內(nèi)存不足,即使你的應(yīng)用是在自托管的服務(wù)器,。更不用說(shuō)只有 512M 內(nèi)存限制的 Heroku,。

其實(shí)我們有更好的辦法。那么如果我們無(wú)法回避GC,,我們可以嘗試讓GC運(yùn)行的時(shí)間點(diǎn)盡量的確定,,并且在閑時(shí)運(yùn)行。例如,,在兩個(gè)request之間,,運(yùn)行GC。這個(gè)很容易通過(guò)配置Unicorn實(shí)現(xiàn),。

對(duì)于Ruby 2.1以前的版本,,有一個(gè)unicorn模塊叫做OobGC:

require 'unicorn/oob_gc'
    use(Unicorn::OobGC, 1)   # "1" 表示"強(qiáng)制GC在1個(gè)request后運(yùn)行"

對(duì)于Ruby 2.1及以后的版本,最好使用gctools(https://github.com/tmm1/gctools):

require 'gctools/oobgc'
use(GC::OOB::UnicornMiddleware)

但在request之間運(yùn)行GC也有一些注意事項(xiàng),。最重要的是,,這種優(yōu)化技術(shù)是可感知的,。也就是說(shuō),用戶(hù)會(huì)明顯感覺(jué)到性能的提升,。但是服務(wù)器需要做更多的工作,。不同于在需要時(shí)才運(yùn)行GC,這種技術(shù)需要服務(wù)器頻繁的運(yùn)行GC. 所以,,你要確定你的服務(wù)器有足夠的資源來(lái)運(yùn)行GC,,并且在其他worker正在運(yùn)行GC的過(guò)程中,有足夠的worker來(lái)處理用戶(hù)的請(qǐng)求,。

2.4 有限的增長(zhǎng)

我已經(jīng)給你展示了一些應(yīng)用會(huì)占用1G內(nèi)存的例子,。如果你的內(nèi)存是足夠的,那么占用這么一大塊內(nèi)存并不是個(gè)大問(wèn)題,。但是Ruby可能不會(huì)把這塊內(nèi)存返還給操作系統(tǒng)。接下來(lái)讓我來(lái)闡述一下為什么,。

Ruby通過(guò)兩個(gè)堆來(lái)分配內(nèi)存,。所有Ruby的對(duì)象在存儲(chǔ)在Ruby自己的堆當(dāng)中。每個(gè)對(duì)象占用40字節(jié)(64位操作系統(tǒng)中),。當(dāng)對(duì)象需要更多內(nèi)存的時(shí)候,,它就會(huì)在操作系統(tǒng)的堆中分配內(nèi)存。當(dāng)對(duì)象被垃圾回收并釋放后,,被占用的操作系統(tǒng)中的堆的內(nèi)存將會(huì)返還給操作系統(tǒng),,但是Ruby自有的堆當(dāng)中占用的內(nèi)存只會(huì)簡(jiǎn)單的標(biāo)記為free可用,并不會(huì)返還給操作系統(tǒng),。

這意味著,,Ruby的堆只會(huì)增加不會(huì)減少。想象一下,,如果你從數(shù)據(jù)庫(kù)讀取了1百萬(wàn)行記錄,,每行10個(gè)列。那么你需要至少分配1千萬(wàn)個(gè)對(duì)象來(lái)存儲(chǔ)這些數(shù)據(jù),。通常Ruby worker在啟動(dòng)后占用100M內(nèi)存,。為了適應(yīng)這么多數(shù)據(jù),worker需要額外增加400M的內(nèi)存(1千萬(wàn)個(gè)對(duì)象,,每個(gè)對(duì)象占用40個(gè)字節(jié)),。即使這些對(duì)象最后被收回,這個(gè)worker仍然使用著500M的內(nèi)存,。

這里需要聲明,, Ruby GC可以減少這個(gè)堆的大小。但是我在實(shí)戰(zhàn)中還沒(méi)發(fā)現(xiàn)有這個(gè)功能,。因?yàn)樵谏a(chǎn)環(huán)境中,,觸發(fā)堆減少的條件很少會(huì)出現(xiàn),。

如果你的worker只能增長(zhǎng),最明顯的解決辦法就是每當(dāng)它的內(nèi)存占用太多的時(shí)候,,就重啟該worker,。某些托管的服務(wù)會(huì)這么做,例如Heroku,。讓我們來(lái)看看其他方法來(lái)實(shí)現(xiàn)這個(gè)功能,。

2.4.1 內(nèi)部?jī)?nèi)存控制

Trust in God, but lock your car 相信上帝,但別忘了鎖車(chē),。(寓意:大部分外國(guó)人都有宗教信仰,,相信上帝是萬(wàn)能的,但是日常生活中,,誰(shuí)能指望上帝能幫助自己呢,。信仰是信仰,但是有困難的時(shí)候 還是要靠自己,。),。有兩個(gè)途徑可以讓你的應(yīng)用實(shí)現(xiàn)自我內(nèi)存限制。我管他們做,,Kind(友好)和hard(強(qiáng)制).

Kind 友好內(nèi)存限制是在每個(gè)請(qǐng)求后強(qiáng)制內(nèi)存大小,。如果worker占用的內(nèi)存過(guò)大,那么該worker就會(huì)結(jié)束,,并且unicorn會(huì)創(chuàng)建一個(gè)新的worker,。這就是為什么我管它做“kind”。它不會(huì)導(dǎo)致你的應(yīng)用中斷,。

獲取進(jìn)程的內(nèi)存大小,,使用 RSS 度量在 Linux 和 MacOS 或者 OS gem 在 windows 上。我來(lái)展示下在 Unicorn 配置文件里怎么實(shí)現(xiàn)這個(gè)限制:

class Unicorn::HttpServer
 KIND_MEMORY_LIMIT_RSS = 150 #MB
 alias process_client_orig process_client
 undef_method :process_client
 def process_client(client)
  process_client_orig(client)
  rss = `ps -o rss= -p #{Process.pid}`.chomp.to_i / 1024
  exit if rss > KIND_MEMORY_LIMIT_RSS
 end
end

硬盤(pán)內(nèi)存限制是通過(guò)詢(xún)問(wèn)操作系統(tǒng)去殺你的工作進(jìn)程,,如果它增長(zhǎng)很多,。在 Unix 上你可以叫 setrlimit 去設(shè)置 RSSx 限制。據(jù)我所知,,這種只在 Linux 上有效,。MacOS 實(shí)現(xiàn)被打破了。我會(huì)感激任何新的信息,。

這個(gè)片段來(lái)自 Unicorn 硬盤(pán)限制的配置文件:

after_fork do |server, worker|
  worker.set_memory_limits
end
class Unicorn::Worker
  HARD_MEMORY_LIMIT_RSS = 600 #MB
  def set_memory_limits
    Process.setrlimit(Process::RLIMIT_AS, HARD_MEMORY_LIMIT * 1024 * 1024)
  end
end

2.4.2 外部?jī)?nèi)存控制

自動(dòng)控制沒(méi)有從偶爾的 OMM(內(nèi)存不足)拯救你,。通常你應(yīng)該設(shè)置一些外部工具。在 Heroku 上,,沒(méi)有必要因?yàn)樗鼈冇凶约旱谋O(jiān)控,。但是如果你是自托管,使用 monit,,god 是一個(gè)很好的主意,,或者其它的監(jiān)視解決方案,。

2.5 優(yōu)化 Ruby GC

在某些情況下,你可以調(diào)整 Ruby GC 來(lái)改善其性能,。我想說(shuō),,這些 GC 調(diào)優(yōu)變得越來(lái)越不重要,Ruby 2.1 的默認(rèn)設(shè)置,,后來(lái)已經(jīng)對(duì)大多數(shù)人有利,。

GC 好的調(diào)優(yōu)你需要知道它是怎么工作的。這是一個(gè)獨(dú)立的主題,,不屬于這編文章,。要了解更多,徹底讀讀 Sam Saffron 的 揭秘 Ruby GC 這篇文章,。在我即將到來(lái)的 Ruby 性能的一書(shū),,我挖到更深的 Ruby GC 細(xì)節(jié)。訂閱這個(gè),,當(dāng)我完成這本書(shū)的 beta 版本會(huì)給你發(fā)送一份郵件,。

我的建議是最好不要改變 GC 的設(shè)置,除非你明確知道你想要做什么,,而且有足夠的理論知識(shí)知道如何提高性能。對(duì)于使用 Ruby 2.1 或之后的版本的用戶(hù),,這點(diǎn)尤為重要,。

我知道只有一種場(chǎng)合 GC 優(yōu)化確實(shí)能帶來(lái)性能的提升。那就是,,當(dāng)你要一次過(guò)載入大量的數(shù)據(jù),。你可以通過(guò)改變?nèi)缦碌沫h(huán)境變量來(lái)達(dá)到減少GC運(yùn)行的頻率:RUBY_GC_HEAP_GROWTH_FACTOR,RUBY_GC_MALLOC_LIMIT,,RUBY_GC_MALLOC_LIMIT_MAX,,RUBY_GC_OLDMALLOC_LIMIT,和 RUBY_GC_OLDMALLOC_LIMIT,。

請(qǐng)注意,,這些變量只適用于 Ruby 2.1 及之后的版本。對(duì)于 2.1 之前的版本,,可能缺少某一個(gè)變量,,或者變量不是使用這個(gè)名字。

RUBY_GC_HEAP_GROWTH_FACTOR 默認(rèn)值 1.8,,它用于當(dāng) Ruby 的堆沒(méi)有足夠的空間來(lái)分配內(nèi)存的時(shí)候,,每次應(yīng)該增加多少。當(dāng)你需要使用大量的對(duì)象的時(shí)候,,你希望堆的內(nèi)存空間增長(zhǎng)的快一點(diǎn),。在這種場(chǎng)合,,你需要增加該因子的大小。

內(nèi)存限制是用于定義當(dāng)你需要向操作系統(tǒng)的堆申請(qǐng)空間的時(shí)候,,GC 被觸發(fā)的頻率,。Ruby 2.1 及之后的版本,默認(rèn)的限額為:

New generation malloc limit RUBY_GC_MALLOC_LIMIT 16M
Maximum new generation malloc limit RUBY_GC_MALLOC_LIMIT_MAX 32M
Old generation malloc limit RUBY_GC_OLDMALLOC_LIMIT 16M
Maximum old generation malloc limit RUBY_GC_OLDMALLOC_LIMIT_MAX 128M

讓我簡(jiǎn)要的說(shuō)明一下這些值的意義,。通過(guò)設(shè)置以上的值,,每次新對(duì)象分配 16M 到 32M 之間,并且舊對(duì)象每占用 16M 到 128M 之間的時(shí)候 (“舊對(duì)象” 的意思是,,該對(duì)象至少被垃圾回收調(diào)用過(guò)一次),, Ruby 將運(yùn)行 GC。Ruby 會(huì)根據(jù)你的內(nèi)存模式,,動(dòng)態(tài)的調(diào)整當(dāng)前的限額值。

所以,,當(dāng)你只有少數(shù)幾個(gè)對(duì)象,,卻占用了大量的內(nèi)存(例如讀取一個(gè)很大的文件到字符串對(duì)象中),,你可以增加該限額,,以減少 GC 被觸發(fā)的頻率。請(qǐng)記住,,要同時(shí)增加 4 個(gè)限額值,,而且最好是該默認(rèn)值的倍數(shù)。

我的建議是可能和其他人的建議不一樣,。對(duì)我可能合適,,但對(duì)于你卻未必。這些文章將介紹,,哪些對(duì) Twitter 適用,,而哪些對(duì) Discourse 適用。

2.6 Profile

有時(shí)候,,這些建議未必就是通用,。你需要弄清楚你的問(wèn)題。這時(shí)候,,你就要使用 profiler,。Ruby-Prof 是每個(gè) Ruby 用戶(hù)都會(huì)使用的工具。

想知道更多關(guān)于 profiling 的知識(shí), 請(qǐng)閱讀 Chris Heald’s 和我的關(guān)于在 Rails 中 使用ruby-prof 的文章,。還有一些也許有點(diǎn)過(guò)時(shí)的關(guān)于 memory profiling 的建議.

2.7 編寫(xiě)性能測(cè)試用例

最后,,提高 Rails 性能的技巧中,雖然不是最重要的,就是確認(rèn)應(yīng)用的性能不會(huì)因你修改了代碼而導(dǎo)致性能再次下降,。Rails 3.x 有一個(gè)附帶了一個(gè) 性能測(cè)試和 profiling 框架 的功能,。對(duì)于 Rails 4, 你可以通過(guò) rails-perftest gem 使用相同的框架,。

3 總結(jié)感言

對(duì)于一篇文章中,,對(duì)于如何提高 Ruby 和 Rails 的性能,要面面俱到,,確實(shí)不可能,。所以,在這之后,,我會(huì)通過(guò)寫(xiě)一本書(shū)來(lái)總結(jié)我的經(jīng)驗(yàn),。如果你覺(jué)得我的建議有用,請(qǐng)登記 mailinglist ,,當(dāng)我準(zhǔn)備好了該書(shū)的預(yù)覽版之后,,將會(huì)第一時(shí)間通知你。現(xiàn)在,,讓我們一起來(lái)動(dòng)手,,讓 Rails 應(yīng)用跑得更快一些吧!

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,,所有內(nèi)容均由用戶(hù)發(fā)布,,不代表本站觀(guān)點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購(gòu)買(mǎi)等信息,,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶(hù) 評(píng)論公約

    類(lèi)似文章 更多