Rò rỉ vật lý
Các loại lỗi mà GC giải quyết dường như (ít nhất là đối với người quan sát bên ngoài) là loại điều mà một lập trình viên biết rõ ngôn ngữ, thư viện, khái niệm, thành ngữ, v.v., sẽ không làm được. Nhưng tôi có thể sai: việc xử lý bộ nhớ thủ công có thực sự phức tạp không?
Đến từ đầu C làm cho việc quản lý bộ nhớ trở nên thủ công và phát âm càng tốt để chúng ta so sánh các thái cực (C ++ chủ yếu tự động hóa quản lý bộ nhớ mà không cần GC), tôi nói "không thực sự" theo nghĩa so sánh với GC khi nó đến rò rỉ . Một người mới bắt đầu và đôi khi thậm chí là một pro có thể quên viết free
cho một cái nhất định malloc
. Nó chắc chắn xảy ra.
Tuy nhiên, có những công cụ như valgrind
phát hiện rò rỉ sẽ ngay lập tức phát hiện ra, khi thực thi mã, khi / khi những lỗi đó xảy ra xuống dòng mã chính xác. Khi được tích hợp vào CI, gần như không thể hợp nhất những lỗi đó và dễ dàng sửa chữa chúng. Vì vậy, nó không bao giờ là một vấn đề lớn trong bất kỳ nhóm / quy trình với các tiêu chuẩn hợp lý.
Cấp, có thể có một số trường hợp thực thi kỳ lạ bay theo radar thử nghiệm free
không được gọi, có lẽ gặp phải lỗi đầu vào bên ngoài tối nghĩa như tệp bị hỏng trong trường hợp có thể hệ thống bị rò rỉ 32 byte hoặc thứ gì đó. Tôi nghĩ điều đó chắc chắn có thể xảy ra ngay cả dưới các tiêu chuẩn kiểm tra khá tốt và các công cụ phát hiện rò rỉ, nhưng cũng sẽ không quá quan trọng để rò rỉ một chút bộ nhớ vào một thứ gần như không bao giờ xảy ra. Chúng ta sẽ thấy một vấn đề lớn hơn nhiều khi chúng ta có thể rò rỉ tài nguyên lớn ngay cả trong các đường dẫn thực thi phổ biến bên dưới theo cách mà GC không thể ngăn chặn.
Thật khó khăn khi không có thứ gì đó giống như dạng giả của GC (đếm tham chiếu, ví dụ) khi thời gian tồn tại của một đối tượng cần được kéo dài cho một số hình thức xử lý hoãn / không đồng bộ, có lẽ bởi một luồng khác.
Con trỏ
Vấn đề thực sự với các hình thức quản lý bộ nhớ thủ công hơn không phải là rò rỉ đối với tôi. Có bao nhiêu ứng dụng gốc được viết bằng C hoặc C ++ mà chúng ta biết thực sự bị rò rỉ? Là nhân Linux bị rò rỉ? MySQL? Khóc 3? Máy trạm âm thanh kỹ thuật số và tổng hợp? Java VM có bị rò rỉ không (nó được triển khai bằng mã gốc)? Photoshop?
Nếu bất cứ điều gì, tôi nghĩ khi chúng ta nhìn xung quanh, các ứng dụng rò rỉ nhất có xu hướng là những ứng dụng được viết bằng cách sử dụng các sơ đồ GC. Nhưng trước khi thực hiện việc thu gom rác, mã gốc có một vấn đề quan trọng không liên quan đến rò rỉ bộ nhớ.
Vấn đề đối với tôi luôn là sự an toàn. Ngay cả khi chúng ta free
ghi nhớ thông qua một con trỏ, nếu có bất kỳ con trỏ nào khác đến tài nguyên, chúng sẽ trở thành con trỏ lơ lửng (không hợp lệ).
Khi chúng tôi cố gắng truy cập vào các điểm của những con trỏ lơ lửng đó, cuối cùng chúng tôi sẽ chạy vào hành vi không xác định, mặc dù hầu như luôn luôn là một vi phạm segfault / truy cập dẫn đến một sự cố nghiêm trọng, ngay lập tức.
Tất cả những ứng dụng gốc mà tôi liệt kê ở trên có khả năng có một hoặc hai trường hợp khó hiểu có thể dẫn đến sự cố chủ yếu do vấn đề này và chắc chắn có một phần công bằng các ứng dụng kém chất lượng được viết bằng mã gốc rất nặng và thường gặp sự cố phần lớn do vấn đề này.
... Và đó là vì quản lý tài nguyên khó khăn cho dù bạn có sử dụng GC hay không. Sự khác biệt thực tế thường là rò rỉ (GC) hoặc sụp đổ (không có GC) khi đối mặt với một sai lầm dẫn đến quản lý tài nguyên sai.
Quản lý tài nguyên: Thu gom rác
Quản lý tài nguyên phức tạp là một quá trình thủ công, khó khăn, không có vấn đề gì. GC không thể tự động hóa bất cứ điều gì ở đây.
Hãy lấy một ví dụ về nơi chúng ta có đối tượng này, "Joe". Joe được tham chiếu bởi một số tổ chức mà anh ta là thành viên. Hàng tháng họ trích một khoản phí thành viên từ thẻ tín dụng của mình.
Chúng tôi cũng có một tài liệu tham khảo đến Joe để kiểm soát cuộc sống của anh ấy. Hãy nói rằng, là lập trình viên, chúng ta không còn cần Joe nữa. Anh ấy bắt đầu làm phiền chúng tôi và chúng tôi không còn cần những tổ chức này, anh ấy đã lãng phí thời gian để giao dịch với anh ấy. Vì vậy, chúng tôi cố gắng quét sạch anh ta khỏi bề mặt trái đất bằng cách xóa tham chiếu huyết mạch của anh ta.
... nhưng chờ đã, chúng tôi đang sử dụng bộ sưu tập rác. Mọi tham chiếu mạnh mẽ đến Joe sẽ giữ anh ta xung quanh. Vì vậy, chúng tôi cũng xóa các tham chiếu đến anh ta khỏi các tổ chức mà anh ta thuộc về (hủy đăng ký anh ta).
... Ngoại trừ rất tiếc, chúng tôi đã quên hủy đăng ký tạp chí của anh ấy! Bây giờ Joe vẫn còn trong ký ức, làm phiền chúng tôi và sử dụng hết tài nguyên, và công ty tạp chí cuối cùng cũng tiếp tục xử lý tư cách thành viên của Joe mỗi tháng.
Đây là lỗi chính có thể khiến nhiều chương trình phức tạp được viết bằng cách sử dụng các chương trình thu gom rác bị rò rỉ và bắt đầu sử dụng càng nhiều bộ nhớ trong thời gian dài hơn và có thể xử lý nhiều hơn (đăng ký tạp chí định kỳ). Họ đã quên xóa một hoặc nhiều tài liệu tham khảo đó, khiến người thu gom rác không thể thực hiện phép thuật của mình cho đến khi toàn bộ chương trình bị tắt.
Chương trình không sụp đổ, tuy nhiên. Nó hoàn toàn an toàn. Nó sẽ tiếp tục tăng cường trí nhớ và Joe sẽ vẫn nán lại xung quanh. Đối với nhiều ứng dụng, loại hành vi rò rỉ này mà chúng ta chỉ cần xử lý nhiều bộ nhớ / xử lý hơn có thể sẽ tốt hơn nhiều so với sự cố cứng, đặc biệt là có bao nhiêu bộ nhớ và khả năng xử lý của máy móc của chúng ta ngày nay.
Quản lý tài nguyên: Hướng dẫn sử dụng
Bây giờ, hãy xem xét lựa chọn thay thế nơi chúng tôi sử dụng con trỏ tới Joe và quản lý bộ nhớ thủ công, như vậy:
Những liên kết màu xanh này không quản lý cuộc sống của Joe. Nếu chúng ta muốn loại bỏ anh ta khỏi bề mặt trái đất, chúng tôi yêu cầu thủ công tiêu diệt anh ta, như vậy:
Bây giờ điều đó thường sẽ để lại cho chúng ta những con trỏ lơ lửng khắp nơi, vì vậy hãy xóa con trỏ cho Joe.
... Rất tiếc, chúng tôi lại mắc lỗi tương tự và quên hủy đăng ký tạp chí của Joe!
Ngoại trừ bây giờ chúng ta có một con trỏ lơ lửng. Khi thuê bao tạp chí cố gắng xử lý phí hàng tháng của Joe, toàn bộ thế giới sẽ bùng nổ - thông thường chúng ta gặp sự cố nghiêm trọng ngay lập tức.
Lỗi quản lý tài nguyên cơ bản tương tự này khi nhà phát triển quên xóa thủ công tất cả các con trỏ / tham chiếu đến tài nguyên có thể dẫn đến nhiều sự cố trong các ứng dụng gốc. Họ không lưu trữ bộ nhớ lâu hơn họ thường chạy vì họ sẽ thường xuyên gặp sự cố trong trường hợp này.
Thế giới thực
Bây giờ ví dụ trên đang sử dụng một sơ đồ đơn giản đến nực cười. Một ứng dụng trong thế giới thực có thể yêu cầu hàng ngàn hình ảnh được ghép lại với nhau để bao quát toàn bộ biểu đồ, với hàng trăm loại tài nguyên khác nhau được lưu trữ trong biểu đồ cảnh, tài nguyên GPU được liên kết với một số trong số chúng, máy gia tốc gắn với người khác, người quan sát được phân phối trên hàng trăm plugin xem một số loại thực thể trong cảnh để thay đổi, người quan sát quan sát người quan sát, âm thanh được đồng bộ hóa với hình ảnh động, v.v ... Vì vậy, có vẻ như thật dễ dàng để tránh sai lầm mà tôi đã mô tả ở trên, nhưng nói chung không có gì đơn giản trong thế giới thực này cơ sở sản xuất cho một ứng dụng phức tạp trải dài hàng triệu dòng mã.
Cơ hội mà một người nào đó, một ngày nào đó, sẽ quản lý tài nguyên ở đâu đó trong cơ sở mã đó có xu hướng khá cao và xác suất đó là như nhau có hoặc không có GC. Sự khác biệt chính là những gì sẽ xảy ra do lỗi này, điều này cũng ảnh hưởng đến khả năng ảnh hưởng của lỗi này sẽ được phát hiện và sửa chữa nhanh như thế nào.
Tai nạn so với rò rỉ
Bây giờ cái nào tệ hơn? Một vụ tai nạn ngay lập tức, hoặc rò rỉ ký ức im lặng nơi Joe chỉ lẩn quẩn một cách bí ẩn?
Hầu hết có thể trả lời câu hỏi sau, nhưng giả sử phần mềm này được thiết kế để chạy hàng giờ liên tục, có thể là vài ngày và mỗi phần mềm của Joe và Jane chúng tôi thêm vào sẽ tăng mức sử dụng bộ nhớ của phần mềm lên một gigabyte. Đây không phải là một phần mềm quan trọng cho nhiệm vụ (sự cố không thực sự giết chết người dùng), mà là một phần mềm quan trọng về hiệu năng.
Trong trường hợp này, một sự cố nghiêm trọng xuất hiện ngay lập tức khi gỡ lỗi, chỉ ra lỗi bạn mắc phải, thực sự có thể tốt hơn là chỉ là một phần mềm bị rò rỉ thậm chí có thể bay theo radar của quy trình thử nghiệm của bạn.
Mặt khác, nếu đó là một phần mềm quan trọng trong nhiệm vụ mà hiệu suất không phải là mục tiêu, chỉ cần không bị sập bởi bất kỳ phương tiện nào có thể, thì thực sự có thể rò rỉ.
Tài liệu tham khảo yếu
Có một loại lai giữa những ý tưởng này có sẵn trong các sơ đồ GC được gọi là tài liệu tham khảo yếu. Với các tài liệu tham khảo yếu, chúng ta có thể có tất cả các tổ chức này Joe tham chiếu yếu nhưng không ngăn anh ta bị xóa khi tham chiếu mạnh (chủ sở hữu / huyết mạch của Joe) biến mất. Tuy nhiên, chúng tôi nhận được lợi ích của việc có thể phát hiện khi Joe không còn ở đây thông qua các tài liệu tham khảo yếu này, cho phép chúng tôi nhận được một loại lỗi dễ tái tạo.
Thật không may, các tài liệu tham khảo yếu không được sử dụng nhiều như chúng có thể được sử dụng, do đó, rất nhiều ứng dụng GC phức tạp có thể dễ bị rò rỉ ngay cả khi chúng có khả năng ít bị hỏng hơn ứng dụng C phức tạp, ví dụ
Trong mọi trường hợp, việc GC có làm cho cuộc sống của bạn dễ dàng hơn hay khó khăn hơn hay không phụ thuộc vào mức độ quan trọng của phần mềm của bạn để tránh rò rỉ, và liệu nó có liên quan đến việc quản lý tài nguyên phức tạp kiểu này hay không.
Trong trường hợp của tôi, tôi làm việc trong một lĩnh vực quan trọng về hiệu năng, nơi các tài nguyên trải rộng từ hàng trăm megabyte đến gigabyte và không giải phóng bộ nhớ đó khi người dùng yêu cầu giải nén vì một lỗi như trên thực sự có thể ít gặp sự cố hơn. Các sự cố rất dễ phát hiện và tái tạo, khiến chúng thường là loại lỗi yêu thích của lập trình viên, ngay cả khi đó là lỗi yêu thích nhất của người dùng và rất nhiều sự cố này sẽ xuất hiện với quy trình kiểm tra lành mạnh trước khi chúng đến tay người dùng.
Dù sao, đó là những khác biệt giữa quản lý bộ nhớ thủ công và GC. Để trả lời câu hỏi ngay lập tức của bạn, tôi sẽ nói rằng quản lý bộ nhớ thủ công là khó khăn, nhưng nó rất ít liên quan đến rò rỉ, và cả hai hình thức quản lý bộ nhớ thủ công và GC vẫn rất khó khăn khi quản lý tài nguyên không tầm thường. Người ta cho rằng GC có nhiều hành vi phức tạp hơn ở đây khi chương trình dường như hoạt động tốt nhưng lại ngày càng tiêu tốn nhiều tài nguyên hơn. Các hình thức thủ công là ít khó khăn hơn, nhưng sẽ sụp đổ và đốt thời gian lớn với những sai lầm như hình trên.