phân bổ tĩnh trong java - tạo heap, stack và vĩnh viễn


117

Gần đây tôi đã đọc rất nhiều về các sơ đồ cấp phát bộ nhớ trong java và có nhiều nghi ngờ khi tôi đọc từ nhiều nguồn khác nhau. Tôi đã thu thập các khái niệm của mình, và tôi yêu cầu xem qua tất cả các điểm và nhận xét về chúng. Tôi đã biết rằng phân bổ bộ nhớ là JVM cụ thể, vì vậy tôi phải nói trước rằng câu hỏi của tôi là Sun cụ thể.

  1. Các lớp (được tải bởi bộ nạp lớp) đi trong một khu vực đặc biệt trên heap: Thế hệ vĩnh viễn
  2. Tất cả thông tin liên quan đến một lớp như tên của lớp, các mảng đối tượng được liên kết với lớp, các đối tượng bên trong được sử dụng bởi JVM (như java / lang / Object) và thông tin tối ưu hóa được đưa vào khu vực Tạo vĩnh viễn.
  3. Tất cả các biến thành viên tĩnh được giữ lại trên vùng Tạo vĩnh viễn.
  4. Đối tượng đi trên một đống khác nhau: Thế hệ trẻ
  5. Chỉ có một bản sao của mỗi phương thức trên mỗi lớp, là phương thức tĩnh hoặc không tĩnh. Bản sao đó được đưa vào khu vực Thế hệ vĩnh viễn. Đối với các phương thức không tĩnh, tất cả các tham số và biến cục bộ đi vào ngăn xếp - và bất cứ khi nào có một lệnh gọi cụ thể về phương thức đó, chúng ta sẽ nhận được một khung ngăn xếp mới được liên kết với nó. Tôi không chắc các biến cục bộ của một phương thức tĩnh được lưu trữ ở đâu. Họ có ở trên đống của Thế hệ vĩnh viễn không? Hoặc chỉ tham chiếu của họ được lưu trữ trong khu vực Tạo vĩnh viễn và bản sao thực sự ở một nơi khác (Ở đâu?)
  6. Tôi cũng không chắc kiểu trả về của một phương thức được lưu trữ ở đâu.
  7. Nếu các đối tượng (trong thế hệ trẻ) cần sử dụng thành viên tĩnh (trong thế hệ vĩnh viễn), chúng được cung cấp tham chiếu đến thành viên tĩnh && chúng được cung cấp đủ không gian bộ nhớ để lưu kiểu trả về của phương thức, v.v.

Cảm ơn bạn đã vượt qua điều này!

Câu trả lời:


152

Đầu tiên, cần phải nói rõ với bạn rằng hiện nay có rất ít người có thể xác nhận những câu trả lời này từ kiến ​​thức đầu tiên. Rất ít người đã làm việc trên các HotSpot JVM gần đây hoặc nghiên cứu chúng ở mức độ chuyên sâu cần thiết để thực sự biết. Hầu hết mọi người ở đây (bao gồm cả tôi) đang trả lời dựa trên những điều họ đã thấy được viết ở nơi khác, hoặc những gì họ đã suy luận. Thông thường những gì được viết ở đây, hoặc trong các bài báo và trang web khác nhau, dựa trên các nguồn khác có thể có hoặc có thể không chính xác. Thường thì nó được đơn giản hóa, không chính xác hoặc chỉ sai đơn giản.

Nếu bạn muốn xác nhận dứt khoát câu trả lời của mình, bạn thực sự cần tải xuống mã nguồn OpenJDK ... và tự nghiên cứu bằng cách đọc và hiểu mã nguồn. Đặt câu hỏi trên SO, hoặc lướt qua các bài báo ngẫu nhiên trên web không phải là một kỹ thuật nghiên cứu học thuật đúng đắn.

Có nói rằng ...

... câu hỏi của tôi là Sun cụ thể.

Vào thời điểm câu hỏi này được đặt ra, Sun Microsystems đã không còn tồn tại. Do đó, câu hỏi là đặc biệt của Oracle. AFAIK, tất cả các triển khai JVM của bên thứ 3 (không nghiên cứu) hiện tại hoặc là các cổng trực tiếp của bản phát hành OpenJDK hoặc là hậu duệ của bản phát hành Sun / Oracle khác.

Các câu trả lời dưới đây áp dụng cho các bản phát hành Oracle Hotspot và OpenJDK và có thể cho hầu hết các bản phát hành khác ... bao gồm cả GraalVM.

1) Các lớp (được tải bởi bộ nạp lớp) đi trong một khu vực đặc biệt trên heap: Thế hệ vĩnh viễn.

Trước Java 8, có.

Kể từ Java 8, không gian PermGen đã được thay thế bằng Metaspace. Các lớp đã được tải và được biên dịch bởi JIT giờ đã đến đó. PermGen không còn tồn tại.

2) Tất cả thông tin liên quan đến một lớp như tên của lớp, các mảng đối tượng được liên kết với lớp, các đối tượng bên trong được sử dụng bởi JVM (như java / lang / Object) và thông tin tối ưu hóa được đưa vào khu vực Tạo vĩnh viễn.

Nhiều hay ít, có. Tôi không chắc ý của bạn về một số điều đó. Tôi đoán rằng "các đối tượng bên trong được sử dụng bởi JVM (như java / lang / Object)" có nghĩa là bộ mô tả lớp bên trong JVM.

3) Tất cả các biến thành viên tĩnh được giữ lại trên khu vực Tạo vĩnh viễn.

Bản thân các biến có. Các biến này (giống như tất cả các biến Java) sẽ giữ các giá trị nguyên thủy hoặc các tham chiếu đối tượng. Tuy nhiên, trong khi các biến thành viên tĩnh nằm trong một khung được cấp phát trong heap permgen, các đối tượng / mảng được tham chiếu bởi các biến đó có thể được cấp phát trong bất kỳ heap nào .

4) Đối tượng đi trên một đống khác nhau: Thế hệ trẻ

Không cần thiết. Các đối tượng lớn có thể được phân bổ trực tiếp vào thế hệ có quyền sử dụng.

5) Chỉ có một bản sao của mỗi phương thức trên mỗi lớp, là phương thức tĩnh hoặc không tĩnh. Bản sao đó được đưa vào khu vực Thế hệ vĩnh viễn.

Giả sử rằng bạn đang tham chiếu đến mã của phương pháp, thì AFAIK có. Nó có thể phức tạp hơn một chút. Ví dụ: mã đó có thể tồn tại ở dạng bytecode và / hoặc mã gốc tại các thời điểm khác nhau trong vòng đời của JVM.

... Đối với các phương thức không tĩnh, tất cả các tham số và biến cục bộ đi vào ngăn xếp - và bất cứ khi nào có một lệnh gọi cụ thể của phương thức đó, chúng ta sẽ nhận được một khung ngăn xếp mới được liên kết với nó.

Đúng.

... Tôi không chắc các biến cục bộ của một phương thức tĩnh được lưu trữ ở đâu. Họ có ở trên đống của Thế hệ vĩnh viễn không? Hoặc chỉ tham chiếu của họ được lưu trữ trong khu vực Tạo vĩnh viễn và bản sao thực sự ở một nơi khác (Ở đâu?)

Không. Chúng được lưu trữ trên ngăn xếp, giống như các biến cục bộ trong các phương thức không tĩnh.

6) Tôi cũng không chắc kiểu trả về của một phương thức được lưu trữ ở đâu.

Nếu ý của bạn là giá trị được trả về bởi một lệnh gọi phương thức (non-void), thì nó sẽ được trả về trên ngăn xếp hoặc trong một thanh ghi máy. Nếu nó được trả về trên ngăn xếp, điều này sẽ mất 1 hoặc hai từ, tùy thuộc vào loại trả về.

7) Nếu các đối tượng (trong thế hệ trẻ) muốn sử dụng thành viên tĩnh (trong thế hệ vĩnh viễn), chúng được cung cấp một tham chiếu đến thành viên tĩnh && chúng được cung cấp đủ không gian bộ nhớ để lưu kiểu trả về của phương thức, v.v. .

Điều đó là không chính xác (hoặc ít nhất, bạn đang không thể hiện bản thân một cách rõ ràng).

Nếu một số phương thức truy cập một biến thành viên tĩnh, những gì nó nhận được là một giá trị nguyên thủy hoặc một tham chiếu đối tượng . Điều này có thể được gán cho một biến hoặc tham số cục bộ (hiện có), được gán cho một thành viên tĩnh hoặc không tĩnh (hiện có), được gán cho một phần tử (hiện có) của một mảng đã được cấp phát trước đó, hoặc chỉ được sử dụng và loại bỏ.

  • Trong mọi trường hợp, bộ nhớ mới không cần phải được cấp phát để giữ một tham chiếu hoặc một giá trị nguyên thủy.

  • Thông thường, một từ bộ nhớ là tất cả những gì cần thiết để lưu trữ một đối tượng hoặc tham chiếu mảng và giá trị nguyên thủy thường chiếm một hoặc hai từ, tùy thuộc vào kiến ​​trúc phần cứng.

  • Trong mọi trường hợp, người gọi không cần phân bổ không gian để chứa một số đối tượng / mảng được trả về bởi một phương thức. Trong Java, các đối tượng và mảng luôn được trả về bằng cách sử dụng ngữ nghĩa truyền theo giá trị ... nhưng giá trị được trả về là một đối tượng hoặc tham chiếu mảng.


Để biết thêm thông tin, vui lòng tham khảo các nguồn sau:

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.