Tôi đang cố gắng hiểu khi nào bộ nhớ được cấp phát từ vùng heap của Ruby được trả về hệ điều hành. Tôi hiểu rằng Ruby không bao giờ trả về bộ nhớ được cấp phát cho nó nhưng tôi vẫn không chắc về hành vi của bộ nhớ heap. tức là những đối tượng không phù hợp với RVALUE 40 byte.Tại sao chương trình Ruby này không trả lại bộ nhớ heap cho hệ điều hành?
Hãy xem xét chương trình sau phân bổ một số chuỗi lớn và sau đó buộc một GC chính.
require 'objspace'
STRING_SIZE = 250
def print_stats(msg)
puts '-------------------'
puts msg
puts '-------------------'
puts "RSS: #{`ps -eo rss,pid | grep #{Process.pid} | grep -v grep | awk '{ print $1,"KB";}'`}"
puts "HEAP SIZE: #{(GC.stat[:heap_sorted_length] * 408 * 40)/1024} KB"
puts "SIZE OF ALL OBJECTS: #{ObjectSpace.memsize_of_all/1024} KB"
end
def run
print_stats('START WORK')
@data=[]
600_000.times do
@data << " " * STRING_SIZE
end
print_stats('END WORK')
@data=nil
end
run
GC.start
print_stats('AFTER FORCED MAJOR GC')
Chạy chương trình này với Ruby 2.2.3 trên MRI nó tạo ra kết quả sau. Sau khi GC chính bị ép buộc, kích thước heap như mong đợi nhưng RSS không giảm đáng kể.
-------------------
START WORK
-------------------
RSS: 7036 KB
HEAP SIZE: 1195 KB
SIZE OF ALL OBJECTS: 3172 KB
-------------------
END WORK
-------------------
RSS: 205660 KB
HEAP SIZE: 35046 KB
SIZE OF ALL OBJECTS: 178423 KB
-------------------
AFTER FORCED MAJOR GC
-------------------
RSS: 164492 KB
HEAP SIZE: 35046 KB
SIZE OF ALL OBJECTS: 2484 KB
So sánh các kết quả này với kết quả sau khi chúng tôi phân bổ một đối tượng lớn thay vì nhiều đối tượng nhỏ hơn.
def run
print_stats('START WORK')
@data = " " * STRING_SIZE * 600_000
print_stats('END WORK')
@data=nil
end
-------------------
START WORK
-------------------
RSS: 7072 KB
HEAP SIZE: 1195 KB
SIZE OF ALL OBJECTS: 3170 KB
-------------------
END WORK
-------------------
RSS: 153584 KB
HEAP SIZE: 1195 KB
SIZE OF ALL OBJECTS: 149064 KB
-------------------
AFTER FORCED MAJOR GC
-------------------
RSS: 7096 KB
HEAP SIZE: 1195 KB
SIZE OF ALL OBJECTS: 2483 KB
Lưu ý giá trị RSS cuối cùng. Chúng tôi dường như đã giải phóng tất cả bộ nhớ mà chúng tôi đã phân bổ cho chuỗi lớn.
Tôi không chắc chắn lý do tại sao ví dụ thứ hai giải phóng bộ nhớ nhưng ví dụ đầu tiên không phải vì chúng đều cấp phát bộ nhớ ngoài vùng heap của Ruby. Đây là một trong số reference có thể cung cấp giải thích nhưng tôi sẽ quan tâm đến những lời giải thích từ người khác.
Việc giải phóng bộ nhớ cho hạt nhân cũng có chi phí. Bộ nhớ không gian người dùng người cấp phát có thể giữ bộ nhớ đó (riêng tư) với hy vọng có thể là được sử dụng lại trong cùng một quy trình và không đưa lại cho hạt nhân để sử dụng trong các quy trình khác.
Đăng ký vào chủ đề này. Tôi cũng rất quan tâm đến điều này. – dimitarvp
Sự khác biệt cơ bản là trong ví dụ thứ nhất, trong đó các đối tượng * mới * 600k được tạo, chỉ trong đối tượng thứ hai. Mặc dù tổng kích thước của dữ liệu * tham chiếu * là giống nhau, ví dụ đầu tiên yêu cầu các vị trí tham chiếu nhiều hơn 600 nghìn lần (có thể là không bao giờ hoặc sau này được khai thác lại cho hệ điều hành). – joanbm
Tôi khuyên bạn nên theo dõi [bài viết] (http://www.sitepoint.com/ruby-uses-memory/) và [giải thích] được liên kết (http://rocket-science.ru/hacking/2013/12/17/ruby-memory-cạm bẫy /) của 'RVALUE's. Tôi không chắc liệu họ có đúng hay không, chỉ có Koichi mà Ko1 có thể biết. Hoặc một số người đam mê quyết tâm mạnh mẽ, phân tích các nguồn Ruby. – joanbm