2013-03-19 28 views
8

Tôi đang cố gắng hiểu dấu chân bộ nhớ của một đối tượng trong Java là gì. Tôi đọc this và các tài liệu khác về đối tượng và bộ nhớ trong Java.Dấu chân bộ nhớ đối tượng Java - Visualvm và java.sizeOf đo lường

Tuy nhiên, khi tôi đang sử dụng hình ảnh sizeof Java library hoặc hình ảnh, tôi nhận được hai kết quả khác nhau mà không có kết quả nào chúng tôi mong đợi theo tham chiếu trước đó (http://www.javamex.com).

Để kiểm tra, tôi đang sử dụng Java SE 7 Developer Preview trên 64-bits Mac với java.sizeof 0.2.1visualvm 1.3.5.

Tôi có ba lớp, TestObject, TestObject2, TestObject3.

public class TestObject 
{ 

} 

public class TestObject2 extends TestObject 
{ 
    int a = 3; 
} 

public class TestObject3 extends TestObject2 
{ 
    int b = 4; 
    int c = 5; 
} 

lớp học chính của tôi:

public class memoryTester 
{ 
    public static void main(String[] args) throws Throwable 
    { 
     TestObject object1 = new TestObject(); 
     TestObject2 object2 = new TestObject2(); 
     TestObject3 object3 = new TestObject3(); 

     int sum = object2.a + object3.b + object3.c; 
     System.out.println(sum); 

     SizeOf.turnOnDebug(); 

     System.out.println(SizeOf.humanReadable(SizeOf.deepSizeOf(object1))); 
     System.out.println(SizeOf.humanReadable(SizeOf.deepSizeOf(object2))); 
     System.out.println(SizeOf.humanReadable(SizeOf.deepSizeOf(object3))); 
    } 
} 

Với java.SizeOf() tôi nhận được:

{ test.TestObject 
} size = 16.0b 
16.0b 

{ test.TestObject2 
a = 3 
} size = 16.0b 
16.0b 

{ test.TestObject3 
b = 4 
c = 5 
} size = 24.0b 
24.0b 

Với VisualVM tôi có:

this (Java frame) TestObject #1 16 
this (Java frame) TestObject2 #1 20 
this (Java frame) TestObject3 #1 28 

Theo tài liệu tôi đọc qua Internet, như tôi đang ở 64-bit, tôi nên có tiêu đề đối tượng là 16 byte, ok cho TestObject.

Sau đó, cho TestObject2 Tôi nên thêm 4 byte cho trường số nguyên cho 20 byte, tôi nên thêm lại 4 byte đệm, cho tổng kích thước 24 byte cho TestObject2. Liệu tôi có sai?

Tiếp tục theo cách đó cho TestObject3, tôi phải thêm 8 byte cho hai trường số nguyên phải cung cấp 32 byte.

VisualVm có vẻ bỏ qua phần đệm trong khi java.sizeOf dường như bỏ lỡ 4 byte như thể đã được đưa vào tiêu đề đối tượng. Tôi có thể thay thế một số nguyên bằng 4 boolean nó cho kết quả tương tự.

Câu hỏi:

Tại sao hai công cụ này cho kết quả khác nhau?

Chúng ta có nên có đệm lót không?

Tôi cũng đọc ở đâu đó (tôi đã không tìm thấy liên kết) giữa một lớp và phân lớp của nó có thể có một số phần đệm, đúng không? Trong trường hợp đó, một cây các lớp kế thừa có thể có một số chi phí bộ nhớ?

Cuối cùng, có một số thông số/tài liệu Java nào mô tả chi tiết những gì Java đang làm không?

Cảm ơn sự giúp đỡ của bạn.

Cập nhật:

Để trả lời bình luận của utapyngo, để có được kích thước của các đối tượng trong VisualVM, tôi tạo ra một heapdump, sau đó trong "Lớp học" phần I kiểm tra cột "kích thước" tiếp theo sau khi cột "trường hợp". Số lượng các thể hiện nếu 1 cho mỗi loại đối tượng.

Để trả lời nhận xét của Nathaniel Ford, tôi đã khởi tạo từng fied và sau đó thực hiện một khoản tiền đơn giản với chúng trong phương thức chính để sử dụng chúng. Nó không thay đổi kết quả.

+0

Chúng tôi không có cách nào để biết điều gì là đúng, nếu một trong hai, mà không thấy logic của họ về cách họ đo mức tiêu thụ bộ nhớ. –

+0

Trong trường hợp của tôi jvisualvm 1.7.0 (Build 110325) trên 64-bit Java 1.7.0-b147 cho 16, 16 và 24. Bạn đang sử dụng phương pháp nào để đo bằng visualvm? – utapyngo

+0

Bạn có thể không nhận được kết quả chính xác mà không gán giá trị cho các trường thành viên 'a',' b' và 'c'. Việc triển khai cơ bản của JVM có thể không yêu cầu nó thực sự cấp phát bộ nhớ cho các trường không được sử dụng, chỉ cấp phát bộ nhớ để giữ con trỏ tới các trường đó. –

Trả lời

2

Có khả năng đệm có thể xảy ra. Nó cũng có thể cho các đối tượng trên stack để có được tối ưu hóa hoàn toàn. Chỉ JVM mới biết được kích thước chính xác tại bất kỳ thời điểm nào. Theo các kỹ thuật như vậy để ước tính kích thước từ bên trong ngôn ngữ Java tất cả có xu hướng không đồng ý, các công cụ gắn vào JVM có xu hướng chính xác nhất. Ba kỹ thuật chính của việc thực hiện sizeof trong Java mà tôi biết là:

  1. serialize đối tượng và trả lại chiều dài của những byte (rõ ràng là sai, nhưng hữu ích để so sánh tương đối)
  2. List item phản ánh, và hằng số kích thước mã hóa cứng cho mỗi trường được tìm thấy trên một đối tượng. có thể được điều chỉnh để chính xác nhưng thay đổi trong JVM và đệm mà JVM có thể hoặc có thể không thực hiện sẽ ném nó.
  3. List item tạo tải của các đối tượng, chạy gc và so sánh những thay đổi về kích thước heap JVM

Không ai trong số những kỹ thuật này là chính xác.

Nếu bạn đang chạy trên Oracle JVM, vào hoặc sau v1.5. Sau đó, có một cách để đọc kích thước của một đối tượng thẳng ra khỏi cấu trúc C được sử dụng bởi thời gian chạy Java. Không phải là một ý tưởng tốt cho sản xuất, và làm cho nó sai sau đó bạn có thể sụp đổ JVM. Nhưng đây là một bài đăng trên blog mà bạn có thể thấy thú vị nếu bạn muốn sử dụng nó: http://highlyscalable.wordpress.com/2012/02/02/direct-memory-access-in-java/

Đối với tài liệu về Java thực sự đang làm, đó là JVM cụ thể, phiên bản cụ thể và có khả năng cấu hình cụ thể. Mỗi triển khai đều miễn phí để xử lý các đối tượng khác nhau. Ngay cả trong phạm vi tối ưu hóa các đối tượng ra hoàn toàn, ví dụ, các đối tượng không được truyền ra từ ngăn xếp được miễn phí không được phân bổ trên heap. Một số JVM thậm chí có thể quản lý để giữ cho đối tượng trong CPU đăng ký hoàn toàn. Không phải trường hợp của bạn ở đây, nhưng tôi bao gồm nó như là một ví dụ về lý do tại sao nhận được kích thước thật của các đối tượng Java là khó khăn.

Vì vậy, tốt nhất để lấy bất kỳ giá trị sizeOf nào bạn nhận được bằng một nhúm muối và coi nó là một chỉ số 'hướng dẫn'.

+0

Tôi sẽ thêm một điểm nữa để đo kích thước của một đối tượng: sử dụng gói Instrument và phương thức getObjectSize(). Như được viết trong tài liệu java, nó chỉ trả về kích thước ước tính của đối tượng. Nhưng tôi nghĩ rằng đó là những gì bạn muốn nói bởi "các công cụ gắn vào JVM có xu hướng chính xác nhất". Tôi đã kiểm tra thư viện java.sizeof đang làm gì và có vẻ như chúng sử dụng đúng phương thức getObjectSize().Tôi mong đợi visualvm để làm như vậy. Vì vậy, trong trường hợp cả hai công cụ sử dụng công cụ java, câu hỏi vẫn còn, tại sao các kết quả khác nhau? Tôi đoán tôi cần phải gửi một thư đến đội visulvm. –

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