2012-12-20 31 views
17

Khi tôi sử dụng JavaScript nhiều hơn như một ngôn ngữ hướng đối tượng cấp cao, tôi thấy mình đang suy nghĩ giống như lập trình viên C/C++ khi tôi kết thúc với các đối tượng. Tôi biết GC sẽ chạy cuối cùng và làm sạch đống lộn xộn của tôi, nhưng có những điều tôi có thể làm để thực sự giúp đỡ nó cùng?Có ý nghĩa khi cố gắng hỗ trợ Trình thu gom rác của JavaScript không?

Ví dụ, tôi có một mảng các đối tượng chính lớn/phức tạp ... mỗi đối tượng chính có thể có mảng và các tham chiếu đối tượng phụ khác bên trong. Nếu tôi làm xong với một đối tượng chính và chỉ loại bỏ nó khỏi mảng, GC có lẽ cuối cùng sẽ tìm ra mọi thứ khác mà đối tượng chỉ vào tất cả, tham chiếu nội bộ vòng tròn và tất cả. Nhưng nó có ý nghĩa khi loại bỏ đối tượng chính khỏi mảng lưu trữ đi qua nó và mảng.length = 0 bất kỳ mảng và tham chiếu = null bất kỳ đối tượng nào để làm cho công việc GC trở nên dễ dàng hơn (vd: xoá bỏ tham chiếu rõ ràng nghĩa là ít hơn cho GC theo dõi)? Loại phá hủy thủ công nếu bạn muốn. Có đáng để làm điều đó hay tôi đang lãng phí thời gian/công sức cho ít/không đạt được?

Tôi cho rằng đây cũng là một lý thuyết chung về câu hỏi GC (Java vv) nhưng tôi chủ yếu quan tâm đến JavaScript cho mục đích của câu hỏi này.

Cảm ơn!

+3

Tôi không thể tin rằng ai đó đã đưa ra một câu hỏi thú vị/hữu ích/không ngu ngốc. +1. –

+0

Tôi thấy câu trả lời này rất thú vị: http://stackoverflow.com/a/4324162/752527 –

Trả lời

4

Điều này có thể phụ thuộc vào bộ thu gom rác cụ thể, do đó câu trả lời sẽ tùy thuộc vào công cụ JavaScript bạn đang sử dụng.

Trước tiên, tôi sẽ lưu ý rằng mã ứng dụng tốt nhất thực hiện hai việc. Nó đạt được các mục tiêu kỹ thuật của nó về chức năng và hiệu suất, và nó là đàn hồi để thay đổi. Mã bổ sung nên phục vụ đủ mục đích để biện minh cho độ phức tạp được thêm vào.

Với những gì đã nói, theo Google's notes on V8, đó là động cơ JavaScript được sử dụng bởi Chrome,

V8 đòi bộ nhớ được sử dụng bởi các đối tượng không còn cần thiết trong một quá trình được gọi là thu gom rác thải. Để đảm bảo phân bổ đối tượng nhanh, tạm ngừng thu gom rác ngắn và không có phân mảnh bộ nhớ nào V8 sử dụng bộ thu gom ngăn chặn, thế hệ, chính xác, thu rác. Điều này có nghĩa là V8:

  • dừng thực hiện chương trình khi thực hiện chu kỳ thu thập rác.
  • chỉ xử lý một phần của đống đối tượng trong hầu hết các chu kỳ thu thập rác. Điều này giảm thiểu tác động của việc dừng ứng dụng.
  • luôn biết chính xác nơi tất cả các đối tượng và con trỏ nằm trong bộ nhớ. Điều này tránh nhận dạng sai đối tượng dưới dạng con trỏ có thể dẫn đến kết quả là trong rò rỉ bộ nhớ.

Trong V8, đống đối tượng được phân thành hai phần: không gian mới, nơi đối tượng được tạo ra, và không gian cũ mà các đối tượng còn sống sót một chu kỳ bộ sưu tập rác được phát huy. Nếu một đối tượng được di chuyển trong chu trình thu gom rác , V8 sẽ cập nhật tất cả các con trỏ đến đối tượng.

Bộ thu gom rác thế hệ có xu hướng di chuyển các đối tượng giữa các đống, nơi tất cả các đối tượng trực tiếp được chuyển vào vùng đích. Bất cứ thứ gì không được chuyển đến đích đều được coi là rác. Nó không rõ ràng như thế nào thu gom rác V8 xác định các đối tượng trực tiếp, nhưng chúng ta có thể xem xét một số triển khai GC khác cho các đầu mối.

Như một ví dụ về hành vi của một thi GC cũng như các tài liệu, đồng thời Mark-Sweep sưu tập Java:

  1. Dừng ứng dụng.
  2. Tạo danh sách các đối tượng có thể truy cập từ mã ứng dụng.
  3. Tiếp tục ứng dụng. Song song, trình thu thập CMS chạy một giai đoạn "đánh dấu", trong đó nó đánh dấu các đối tượng có thể truy cập quá mức là "không rác". Vì điều này song song với việc thực hiện chương trình, nó cũng theo dõi các thay đổi tham chiếu được thực hiện bởi ứng dụng.
  4. Dừng ứng dụng.
  5. Chạy giai đoạn thứ hai ("nhận xét") để đánh dấu các đối tượng mới có thể truy cập.
  6. Tiếp tục ứng dụng. Song song, nó "quét" tất cả các đối tượng được xác định là rác và đòi lại các khối đống.

Về cơ bản, đó là biểu đồ truyền tải, bắt đầu từ một nút cụ thể được đặt. Vì các đối tượng bị ngắt kết nối không thể truy cập được, nên sự kết nối của chúng với các đối tượng bị ngắt kết nối khác không nên đi vào hoạt động.

Có giấy tờ tốt, nếu có ngày tháng, trắng trên đường thu gom rác thải Java hoạt động tại http://www.oracle.com/technetwork/java/javase/memorymanagement-whitepaper-150215.pdf. Bộ sưu tập rác không phải là duy nhất cho Java, vì vậy tôi nghi ngờ một số điểm tương đồng giữa các phương pháp khác nhau được thực hiện bởi các máy ảo Java và các thời gian chạy khác như các công cụ JavaScript.

Raymond Chen đã viết blog post chỉ ra rằng bộ nhớ đi bộ mà bạn sắp giải phóng có thể có tác động tiêu cực đến hiệu suất. Bối cảnh xung quanh giải phóng bộ nhớ bằng tay khi tắt ứng dụng. Vì các khối có thể đã được hoán đổi vào đĩa, hành vi duyệt qua các tham chiếu có thể khiến các khối đó được hoán đổi. Trong trường hợp này, chương trình đang thực hiện một quá trình truyền tải các khối đã được đánh dấu là có sẵn và không bị ảnh hưởng. Vì vậy, trong một tình huống mà hệ điều hành có thể đã hoán đổi một số khối, hành động "hỗ trợ" bộ thu gom rác, đặc biệt là đối tượng tồn tại lâu hơn, có thể sẽ làm chậm mọi thứ.

Và nếu bạn không tạo đủ dữ liệu để lo ngại về việc hoán đổi, thì người thu gom rác hợp lý sẽ không mất nhiều thời gian để thông báo.

Vì vậy, rất có thể là không đáng để nỗ lực và có thể phản tác dụng. Mặc dù nó có thể làm cho tinh thần để thả các tài liệu tham khảo để heap "dominators". Đây là những đối tượng, nếu được thu thập, sẽ cho phép thu thập nhiều đối tượng khác. Vì vậy, hãy thả tham chiếu đến chính bộ sưu tập chứ không phải từng mục trong bộ sưu tập.

+1

thú vị, cảm ơn. nó phụ thuộc vào việc thực hiện tất nhiên, nhưng phần này có thể là một chìa khóa cất cánh: "vì các đối tượng bị ngắt kết nối không thể truy cập được, kết nối của chúng với các đối tượng bị ngắt kết nối khác sẽ không được phát" – mark

+0

Nếu không có tham chiếu nào tồn tại một phần của một đồ thị đối tượng, đi bộ đồ thị để phá vỡ các tham chiếu nội bộ sẽ là một sự lãng phí công sức. Trong trường hợp các phần lớn của đồ thị tham chiếu hết hiệu lực nhưng một số phần nhỏ hơn có thể vẫn hữu ích và có thể có tham chiếu nhắm mục tiêu, phá hủy tham chiếu đến các phần vô dụng của biểu đồ có thể cần thiết để ngăn chặn việc sử dụng bộ nhớ không bị tăng. – supercat

+0

Đồng ý, trong trường hợp bạn không mong đợi đối tượng cha mẹ đủ điều kiện để thu thập, bạn vẫn có thể loại bỏ các tham chiếu riêng lẻ khi bạn biết chúng không còn cần thiết nữa. – GargantuChet

3

Những người rất thông minh đã làm việc rất chăm chỉ trên các mô hình thu gom rác thải đó. Các tỷ lệ cược rằng bất cứ điều gì bạn làm là sẽ cải thiện hiệu suất một cách ồ ạt so với những gì họ thực hiện là tương đối thấp.

Nếu thu gom rác thải đang trở thành một chi phí lớn cho bạn, bạn đang có khả năng tốt hơn hết tập trung vào việc giảm số lượng các đối tượng phải được thu gom rác (xem xét Object Pool Pattern)

5

Hiếm khi.

Điểm khác biệt với không bao giờ.

Nói chung, nếu bạn phát triển một cách hợp lý, các đối tượng không sử dụng sẽ rơi ra khỏi phạm vi phù hợp và Bộ thu gom rác sẽ hoạt động như mong đợi. Và trừ khi bạn thực sự hiểu những gì bạn đang làm, những nỗ lực để giúp Garbage Collector làm công việc của mình thường không hoạt động như dự định. Bộ sưu tập rác là một lĩnh vực đã trải qua quá trình tối ưu hóa đáng kể bởi những người tạo ra các công cụ Javascript khác nhau. Nói chung, bạn không nên gây rối với nó, trừ khi:

  • Bạn có chứng minh cho chính mình với những con số khó khăn từ các công cụ phân tích rằng có một nhu cầu thực sự, và
  • Bạn có thể chứng minh sự hiểu biết thực sự của gì thực sự cần phải thay đổi theo thứ tự để giúp Bộ thu gom rác.

Không dễ dàng đạt được điều này.

Vì vậy, có thể câu trả lời hay nhất là trừ khi bạn đã đủ nâng cao để hiểu ngoại lệ, có thể bạn không nên lo lắng về điều này.