Computer >> Máy Tính >  >> Lập trình >> Ruby

Lập hồ sơ phân bổ bộ nhớ của Ruby với TCmalloc

Cấp phát bộ nhớ hoạt động như thế nào trong Ruby?

Ruby có bộ nhớ theo từng phần, được gọi là các trang, các đối tượng mới được lưu ở đây.

Sau đó…

Khi các trang này đầy, cần thêm bộ nhớ.

Ruby yêu cầu thêm bộ nhớ từ hệ điều hành với malloc chức năng.

malloc này chức năng là một phần của chính hệ điều hành, nhưng có những cách triển khai thay thế mà bạn có thể sử dụng.

Một trong những cách triển khai đó là tcmalloc của Google.

TCmalloc là một phần của bộ Công cụ Hiệu suất của Google.

Bạn có thể sử dụng các công cụ này để khám phá chính xác cách Ruby phân bổ bộ nhớ.

Và cảm ơn LD_PRELOAD biến môi trường (trong Linux), chúng tôi có thể thay thế malloc của hệ thống của bạn hàm với tcmalloc.

Như thế này :

 LD_PRELOAD ="/ usr / lib / libtcmalloc.so" ruby ​​-e "đặt 123" 

Nhưng điều đó chỉ tải thư viện, nó chưa cho phép thu thập dữ liệu nào.

Hãy xem điều đó được thực hiện như thế nào.

Bật hồ sơ

Bạn có thể bật hồ sơ của tcmalloc bằng một biến môi trường bổ sung (HEAPPROFILE ).

 LD_PRELOAD ="/ usr / lib / libtcmalloc.so" HEAPPROFILE =/ tmp / profile ruby ​​-e "đặt 123" 

Điều này sẽ tạo ra kết quả sau:

 Bắt đầu theo dõi hồ sơ heap123Dumping heap vào /tmp/profile.0001.heap (Đang thoát, 2 MB đang được sử dụng) 

Tại đây, bạn sẽ thấy xác nhận rằng trình cấu hình đã được kích hoạt.

Sau đó, chúng tôi thấy :

  • Đầu ra của chương trình
  • Tên tệp (profile.0001.heap )
  • Dung lượng bộ nhớ mà chương trình của chúng tôi sử dụng (2 MB )

Để đọc tệp này, bạn sẽ cần một công cụ khác đi kèm với tcmalloc.

 pprof --text `which ruby` /tmp/profile.0001.heap | đầu -10 

Điều này sẽ tạo ra kết quả sau:

 Tổng:2,4 MB 1,1 44,7% 44,7% 1,1 44,7% 0x00005570fa4df074 0,7 27,8% 72,5% 0,7 27,8% 0x00005570fa4e0c09 0,4 15,3% 87,8% 0,4 15,3% 0x00005570fa4db460 0,1 5,9% 93,7% 0,1 5,9% 0x000055 3,2% 96,9% 0,1 % 0x00005570fa6349a0 0,0 1,4% 98,3% 0,0 1,4% 0x00005570fa589924 0,0 0,3% 98,6% 0,0 0,3% 0x00005570fa59c4f2 0,0 0,3% 98,8% 0,0 0,3% 0x00005570fa4db48a 0,0 0,2% 99,0% 0,0 0,2% 0x00005570fa59c4dbaa5 <0,0%> 

Chà, đó chỉ là một loạt các địa chỉ bộ nhớ! Bạn cần một phiên bản Ruby với các ký hiệu gỡ lỗi để có thể xem tên hàm.

Sau đó, bạn sẽ nhận được đầu ra này :

 Sử dụng tệp cục bộ ruby ​​Sử dụng tệp cục bộ /tmp/profile.0001.heap.Tổng:2,9 MB 1,0 36,2% 36,2% 1,0 36,2% objspace_xmalloc0 0,7 26,1% 62,4% 0,7 26,1% align_malloc 0,5 18,8% 81,1% 0,5 18,8% objspace_xcalloc 0,3 9,9% 91,0% 0,3 9,9% stack_chunk_alloc 0,1 3,7% 94,7% 0,1 3,7% objspace_xrealloc 0,1 2,7% 97,4% 0,1 2,7% Init_Method 0,0 1,3% 98,7% 0,0 1,7% onig_new_with_source 0,0 0,4% 99,2% 0,8 26,6% heap_page_allocate 0,0 0,2% 99,4 % 0.0 0,2% add_bitset 

Những gì bạn thấy ở đây là lượng bộ nhớ được phân bổ theo các chức năng của MRI.

Thật thú vị khi biết rằng aligned_malloc là hàm được sử dụng để cấp phát các trang mới cho các đối tượng Ruby, stack_chunk_alloc được chính GC sử dụng trong giai đoạn đánh dấu và objspace_xmalloc0 / objspace_xcalloc phân bổ không gian cho chuỗi, mảng và bất kỳ dữ liệu nào khác không phù hợp với RVALUE cấu trúc.

Bây giờ:

TCmalloc không biết gì về các đối tượng Ruby, điều duy nhất nó làm là theo dõi các lệnh gọi đến malloc, calloc &realloc để tìm ra dung lượng bộ nhớ được yêu cầu.

Nếu bạn muốn có một kết xuất đống ở cấp độ Ruby, bạn có thể sử dụng ObjectSpace.dump_all . Điều này cung cấp cho bạn một tệp JSON với tất cả các đối tượng trực tiếp trong ứng dụng của bạn và kích thước bộ nhớ của chúng.

Nhưng cái gì tcmalloc có thể cho bạn thấy là hình dung của tất cả các hàm C yêu cầu bộ nhớ.

 pprof --web `which ruby` /tmp/profile.0001.heap 

Thao tác này sẽ mở Chrome hoặc Firefox với tệp SVG trông giống như sau:

Lập hồ sơ phân bổ bộ nhớ của Ruby với TCmalloc

TCmalloc không chỉ cung cấp cho bạn khả năng lập hồ sơ tuyệt vời này mà khi sử dụng nó, bạn còn có thể tăng hiệu suất ứng dụng của mình lên 4-9%! Bạn cũng có thể thử jemalloc , là một malloc khác triển khai cũng bao gồm một trình mô tả.

Tóm tắt

Bạn đã học cách sử dụng gperftools (Công cụ Hiệu suất của Google) để trực quan hóa và phân tích việc sử dụng bộ nhớ của trình thông dịch Ruby.

Cảm ơn vì đã đọc! 🙂