2013-02-20 46 views
6

Mã ở cuối câu hỏi này hơi dài nhưng về cơ bản tạo một vài đối tượng và xác định kích thước của chúng trong bộ nhớ. Tôi thực thi mã với các thông số JVM sau (TLAB để tránh phân bổ bộ nhớ đoạn và được cho là có được số liệu sử dụng bộ nhớ chính xác):Đo chính xác kích thước đối tượng

-server -Xms2000m -Xmx2000m -verbose:gc -XX:-UseTLAB 

tôi chạy đoạn code trên 64 bit Hotspot JVM và nhận được kết quả như sau:

Java HotSpot (TM) 64-Bit server VM
Object: 16 byte

Object với 1 int: 16 byte
Object với 2 ints: 24 byte
Object với 3 ints: 24 byte

Object với 1 dài: 24 byte
Object với 2 chờ đợi: 32 byte
Object với 3 chờ đợi: 40 byte

Object với 1 tài liệu tham khảo: 16 byte
đối tượng với sự tham khảo 2: 24 byte
đối tượng với sự tham khảo 3: 24 byte

tôi kết luận rằng:

  • đối tượng mất 12 byte, căn chỉnh thành 16 byte.
  • một int mất 4 byte (1 đối tượng với một int là 12 + 4 = vẫn 16 byte, với 2 ints: 12 + 8 = 20 liên kết đến 24 byte)
  • dài mất 8 byte (1 đối tượng với một dài là 12 + 8 = 20 byte, thẳng đến 24 byte)

Nhưng tôi đấu tranh để hiểu tại sao tài liệu tham khảo không sử dụng không gian nhiều như long s.

Vì tham chiếu là 8 byte trên JVM 64 bit, kết luận rõ ràng là phương pháp đo lường có lỗi *. Bạn có thể giải thích những gì đang xảy ra và những gì có thể được thực hiện để sửa chữa nó?

* Ghi chú:
- không GC chạy trong khi đo.
- bằng cách sử dụng lược tả Netbeans cho kết quả tương tự.

public class TestMemoryReference { 

    private static final int SIZE = 100_000; 
    private static Runnable r; 
    private static Object o = new Object(); 
    private static Object o1 = new Object(); 
    private static Object o2 = new Object(); 
    private static Object o3 = new Object(); 

    public static class ObjectWith1Int { int i; } 
    public static class ObjectWith2Ints { int i, j; } 
    public static class ObjectWith3Ints { int i, j, k; } 
    public static class ObjectWith1Long { long i; } 
    public static class ObjectWith2Longs { long i, j; } 
    public static class ObjectWith3Longs { long i, j, k; } 
    public static class ObjectWith1Object { Object o = o1; } 
    public static class ObjectWith2Objects { Object o = o1; Object p = o2; } 
    public static class ObjectWith3Objects { Object o = o1; Object p = o2; Object q = o3; } 

    private static void test(Runnable r, String name, int numberOfObjects) { 
     long mem = Runtime.getRuntime().freeMemory(); 
     r.run(); 
     System.out.println(name + ":" + (mem - Runtime.getRuntime().freeMemory())/numberOfObjects + " bytes "); 
    } 

    public static void main(String[] args) throws Exception { 
     System.out.println(System.getProperty("java.vm.name") + " "); 

     r = new Runnable() { public void run() { for (int i = 0; i < SIZE; i++) o = new Object(); } }; 
     test(r, "Object", SIZE); 

     r = new Runnable() { public void run() { for (int i = 0; i < SIZE; i++) o = new ObjectWith1Int(); } }; 
     test(r, "Object with 1 int", SIZE); 

     r = new Runnable() { public void run() { for (int i = 0; i < SIZE; i++) o = new ObjectWith2Ints(); } }; 
     test(r, "Object with 2 ints", SIZE); 

     r = new Runnable() { public void run() { for (int i = 0; i < SIZE; i++) o = new ObjectWith3Ints(); } }; 
     test(r, "Object with 3 ints", SIZE); 

     r = new Runnable() { public void run() { for (int i = 0; i < SIZE; i++) o = new ObjectWith1Long(); } }; 
     test(r, "Object with 1 long", SIZE); 

     r = new Runnable() { public void run() { for (int i = 0; i < SIZE; i++) o = new ObjectWith2Longs(); } }; 
     test(r, "Object with 2 longs", SIZE); 

     r = new Runnable() { public void run() { for (int i = 0; i < SIZE; i++) o = new ObjectWith3Longs(); } }; 
     test(r, "Object with 3 longs", SIZE); 

     r = new Runnable() { public void run() { for (int i = 0; i < SIZE; i++) o = new ObjectWith1Object(); } }; 
     test(r, "Object with 1 reference", SIZE); 

     r = new Runnable() { public void run() { for (int i = 0; i < SIZE; i++) o = new ObjectWith2Objects(); } }; 
     test(r, "Object with 2 references", SIZE); 

     r = new Runnable() { public void run() { for (int i = 0; i < SIZE; i++) o = new ObjectWith3Objects(); } }; 
     test(r, "Object with 3 references", SIZE); 
    } 
} 

Trả lời

5

Kể từ tài liệu tham khảo là 8 byte trên 64-bit JVM

này được giả định có khả năng-thiếu sót của mình.

HotSpot là có thể sử dụng "compressed oops" sử dụng giá trị 32-bit để tham khảo trong một số nơi JVM (tôi nhấn mạnh):

nào oops được nén?

Trong một JVM chế độ ILP32 hoặc cờ UseCompressedOops bị tắt ở chế độ LP64, tất cả các vòng là kích thước từ máy gốc.

Nếu UseCompressedOops là đúng, sau oops trong đống sẽ được nén:

  • lĩnh vực klass của mọi đối tượng
  • mọi lĩnh vực dụ oop
  • mọi phần tử của một mảng oop (objArray)

I nghi ngờ đây là những gì đang xảy ra trong trường hợp của bạn.

thử nghiệm nó bằng cách sử dụng

-XX:-UseCompressedOops 

hoặc

-XX:+UseCompressedOops 

Trên máy tính của tôi, theo mặc định tôi nhận được kết quả tương tự như bạn, nhưng với -XX:-UseCompressedOops tôi thấy:

Object:16 bytes 
Object with 1 int:24 bytes 
Object with 2 ints:24 bytes 
Object with 3 ints:32 bytes 
Object with 1 long:24 bytes 
Object with 2 longs:32 bytes 
Object with 3 longs:40 bytes 
Object with 1 reference:24 bytes 
Object with 2 references:32 bytes 
Object with 3 references:40 bytes 

... có lẽ gần hơn với những gì bạn mong đợi :)

+0

Aargh - Tôi nghĩ rằng 'UseCompressedOops' mặc định là false - nó quay ra nó được kích hoạt theo mặc định. Vâng phát hiện. – assylias

+0

@assylias: Xem bản chỉnh sửa của tôi để biết cách bật/tắt. –

0

Kích thước của đối tượng Java được biết khi lớp được xác định.

Sử dụng bộ nhớ của các đối tượng Java: chung http://www.javamex.com/tutorials/memory/object_memory_usage.shtml

+0

Thiết bị đo đạc đôi khi ít chính xác hơn so với phép đo trực tiếp. Và liên kết không giải quyết jvms 64 bit với tùy chọn con trỏ nén. – assylias

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