2010-03-15 39 views
46

Bộ nhớ heap là rác được thu thập trong Java.Thùng rác có được thu thập trong Java không?

Rác ngăn xếp có được thu thập không?

Bộ nhớ ngăn xếp được khôi phục như thế nào?

+10

Ngăn xếp là thuật toán thu thập rác gốc. Ngay cả C cũng có một đống rác được thu thập! – jrockway

+0

C, C++, Java không có bộ sưu tập rác ngăn xếp. Ngoài ra, chỉ có Java cung cấp bộ sưu tập đống rác. (từ ba đề cập ở trên) –

Trả lời

28

Ngăn xếp không phải là rác được thu thập trong Java.

Ngăn xếp được phân bổ cho cuộc gọi phương thức đã cho sẽ được giải phóng khi phương thức trả về. Vì đó là cấu trúc LIFO rất đơn giản nên không cần thu gom rác thải.

Một nơi mà ngăn xếp và bộ sưu tập rác tương tác là tham chiếu trên ngăn xếp là rễ GC (có nghĩa là chúng là các tham chiếu gốc từ đó khả năng truy cập được quyết định).

+11

Để chính xác, ngăn xếp không chứa bất kỳ thứ gì có thể được thu gom rác. Những thứ duy nhất mà nó chứa là các tham chiếu đến các đối tượng và các giá trị của các kiểu nguyên thủy. Thứ duy nhất có thể thu gom rác là vật thể. Hãy nhận biết sự khác biệt giữa một đối tượng và một tham chiếu đến nó. –

+0

@Roland: đó là những gì tôi đã nói. Gốc GC là các tham chiếu *, không phải là các đối tượng. –

+0

Tôi biết. Tôi chỉ nghĩ rằng đối với các từ ngữ của câu hỏi này, nó sẽ là tốt để được rất rõ ràng về chủ đề này và để giải thích nó có thể nhiều hơn cần thiết. –

32

Bộ nhớ trên ngăn chứa các tham số phương pháp và biến cục bộ (chính xác: tham chiếu cho đối tượng và biến cho các kiểu nguyên thủy). Điều đó sẽ tự động bị xóa nếu bạn rời khỏi phương thức. Nếu các biến là các tham chiếu (đối tượng) thì chính các đối tượng đó nằm trên đống và được xử lý bởi bộ thu gom rác.

Vì vậy, ngăn xếp không phải là rác được thu thập theo cách giống như đống, nhưng ngăn xếp là một hình thức quản lý bộ nhớ tự động trong chính nó (mà trước khi thu thập rác).

A more detailed answer is given by Thomas Pornin, hãy xem xét để biết thêm chi tiết.

0

Không ai, dữ liệu được đẩy và xuất hiện từ ngăn xếp khi bạn có biến bên trong trong phương thức, trong khi thực hiện cuộc gọi phương thức, v.v. Bạn không cần phải quan tâm đến điều này.

8

Phần ngăn xếp của bộ nhớ hoạt động giống như một "ngăn xếp". Tôi biết nó nghe có vẻ xấu, nhưng đó chính xác là cách nó hoạt động. Dữ liệu được thêm vào đầu, trên đầu trang của mỗi khác (pushed onto the stack) và được tự động loại bỏ khỏi đầu (popped off the stack) khi chương trình của bạn chạy. Nó không phải là rác thu thập được - và nó không cần phải được kể từ khi bộ nhớ đó được tự động khai hoang khi dữ liệu được bật ra khỏi ngăn xếp. Và khi tôi nói khai hoang tôi không có nghĩa là nó được de-phân bổ - nó chỉ là vị trí trong bộ nhớ ngăn xếp nơi dữ liệu tiếp theo sẽ được lưu trữ được giảm, khi dữ liệu được bật ra.

Tất nhiên đó không phải là để nói rằng bạn không cần phải lo lắng gì cả về ngăn xếp. Nếu bạn chạy hàm đệ quy nhiều lần, nó sẽ sử dụng hết tất cả không gian ngăn xếp. Tương tự nếu bạn gọi nhiều hàm, đặc biệt nếu chúng có nhiều tham số và/hoặc biến cục bộ.

Nhưng dòng dưới cùng là bộ nhớ của ngăn xếp được sử dụng và khai hoang khi các hàm vào và rời khỏi phạm vi - tự động. Vì vậy, vào cuối chương trình của bạn thực hiện tất cả các bộ nhớ stack sẽ được miễn phí và sau đó phát hành trở lại hệ điều hành.

1

Tất cả các đối tượng trong Java được phân bổ trên heap. (Ít nhất là theo các thông số đi, việc thực hiện thực tế có thể phân bổ chúng trên stack nếu họ minh bạch cư xử như thể họ đang trên đống.)

Chính xác những gì được thu là một chút tinh tế. Nếu tham chiếu duy nhất cho một đối tượng nằm trong một khung ngăn xếp duy nhất, và nó có thể được hiển thị rằng tham chiếu sẽ không được sử dụng một lần nữa, sau đó đối tượng có thể được thu thập. Nếu đối tượng chỉ được sử dụng để đọc một trường, thì trường đó đọc có thể được tối ưu hóa về phía trước và đối tượng được thu thập sớm hơn bạn có thể mong đợi.

Điều này thường không quan trọng trừ khi bạn đang sử dụng finalisers (hoặc có lẽ là Reference s).Trong trường hợp đó, bạn nên cẩn thận và sử dụng khóa/dễ bay hơi để thực thi mối quan hệ happens-before.

Khi chuỗi dừng, sau đó thường toàn bộ ngăn xếp sẽ được deallocated.

1

Mọi thứ nằm trên ngăn xếp được xử lý như là rễ toàn cầu bởi một bộ thu gom rác. Vì vậy, có, bạn chắc chắn có thể nói rằng ngăn xếp là "rác thu thập".

14

Ngăn xếp có thể là rác được thu thập. Tuy nhiên, trong hầu hết các triển khai JVM, nó được xử lý như, tốt, một "ngăn xếp", theo định nghĩa ngăn cản việc thu gom rác thải.

Thứ mà chúng tôi gọi là ngăn xếp là sự tích lũy các ngữ cảnh kích hoạt phương thức : một khe để lưu con trỏ lệnh. Ngữ cảnh kích hoạt không thể truy cập được từ chính ngôn ngữ Java. Một bối cảnh trở nên vô dụng khi phương thức thoát (với một return hoặc vì một ngoại lệ được ném). Nó xảy ra khi một phương thức A gọi phương thức B, nó được đảm bảo rằng khi A lấy lại quyền kiểm soát, bối cảnh cho B đã trở nên vô dụng. Điều này ngụ ý rằng toàn bộ thời gian của bối cảnh cho B là sự sắp xếp của vòng đời của bối cảnh A. Vì vậy, các ngữ cảnh kích hoạt (cho một chuỗi nhất định) có thể được phân bổ với một kỷ luật LIFO ("Cuối cùng, Đầu tiên"). Nói cách đơn giản hơn, một ngăn xếp: một bối cảnh kích hoạt mới được đẩy lên trên cùng của chồng bối cảnh, và ngữ cảnh trên cùng sẽ là người đầu tiên được xử lý.

Trong thực tế, các ngữ cảnh kích hoạt (còn gọi là khung ngăn xếp) được ghép nối, theo thứ tự ngăn xếp, trong một khu vực chuyên dụng. Khu vực đó thu được từ hệ điều hành khi bắt đầu luồng và hệ điều hành sẽ lấy lại nó khi luồng kết thúc. Phía trên cùng của ngăn xếp được chỉ định bởi một con trỏ cụ thể, thường chứa trong một thanh ghi CPU (điều này phụ thuộc vào việc JVM có đang diễn giải hay biên dịch mã) hay không. "Con trỏ đến ngữ cảnh của người gọi" là ảo; ngữ cảnh của người gọi nhất thiết phải nằm ngay bên dưới theo thứ tự ngăn xếp. GC không can thiệp: khu vực cho ngăn xếp được tạo và thu hồi đồng bộ, từ chính hoạt động của luồng. Đây cũng là cách nó hoạt động trong nhiều ngôn ngữ như C, không có GC.

Hiện tại, không có gì ngăn cản việc triển khai JVM thực hiện cách khác, ví dụ: phân bổ bối cảnh kích hoạt trong heap và thu thập chúng bởi GC. Điều này thường không được thực hiện trong Java Virtual Machines vì ​​việc phân bổ stack nhanh hơn. Nhưng một số ngôn ngữ khác cần phải làm những việc như vậy, nhất là những người chơi với continuations trong khi vẫn sử dụng GC (ví dụ: Scheme và chức năng call-with-current-continuation), vì các trò chơi đó vi phạm quy tắc LIFO được giải thích ở trên.

+0

+1 cho ngữ cảnh và ngăn xếp kích hoạt phương thức phân biệt thực sự. – sleske

+0

Cũng cần lưu ý rằng trên một số nền tảng (đặc biệt là trên các hệ thống nhúng), các con trỏ hướng dẫn đã lưu vào một vùng lưu trữ hoàn toàn khác với các đối số hàm, biến cục bộ, v.v. hệ thống), điều này có thể cung cấp sự bảo vệ đáng kể chống lại việc thực thi mã không đúng. Hơn nữa, một thiết kế như vậy có thể tăng tốc mọi thứ bằng cách tránh cần phải dành thời gian lưu bộ nhớ hoặc tải lại bộ đếm chương trình khi nhập/thoát chức năng (ngăn xếp phần cứng hoạt động trực tiếp trên bộ đếm chương trình bỏ qua bus bộ nhớ). – supercat

4

Nếu bạn tham khảo bộ nhớ được sử dụng trên ngăn xếp, nó không phải là rác được thu thập.
Máy ảo java sử dụng các lệnh bytecode rõ ràng để dự trữ và giải phóng bộ nhớ trên ngăn xếp, các hướng dẫn này được tạo bởi trình biên dịch và quản lý thời gian tồn tại của nguyên thủy như int, boolean, double và object-references trên stack.
Đã có kế hoạch triển khai tối ưu hóa cuộc gọi đuôi, điều này sẽ xóa một số mục khỏi ngăn xếp khi chúng được biết là chúng không còn được sử dụng nữa, nhưng tôi không biết bất kỳ jvm nào đã hỗ trợ điều này.
Vì vậy, không có bộ sưu tập rác nào cho chính ngăn xếp đó, chỉ có trình biên dịch tạo ra các hướng dẫn push và pop để quản lý việc sử dụng bộ nhớ.

Bản thân ngăn xếp là một phần của chuỗi. Ngăn xếp được cấp phát khi đối tượng luồng được tạo và rác được thu thập sau khi chuỗi được kết thúc và đối tượng chuỗi không còn được tham chiếu nữa.

0

No. Ngăn xếp không phải là rác được thu thập trong Java. Mỗi thread có stack riêng của mình và bao gồm:

  1. giá trị Phương pháp cụ thể (mà là ngắn ngủi) và
  2. Tài liệu tham khảo cho các đối tượng, tạo ra trên heap, và đang được gọi bằng phương pháp

Các giá trị này được đẩy dưới dạng khung ngăn xếp vào ngăn xếp cho mọi cuộc gọi phương thức. Kể từ khi ngăn xếp theo thứ tự 'Last-in First-out', vào cuối mỗi cuộc gọi phương thức, mỗi khung ngăn xếp chứa tất cả dữ liệu phương thức cụ thể và tham chiếu đến các đối tượng, nếu có, được bật ra.

Do đó, dữ liệu trong ngăn xếp sẽ tự động được làm sạch khi phương pháp/chương trình nằm ngoài phạm vi.

Các vấn đề liên quan