2009-05-22 38 views
7

Tôi đang cố tải một tệp .class java động và gọi nó bằng cách phản chiếu.Việc tải lớp Java chạy cực kỳ chậm?

Tôi có một lớp được gọi là Foo; nó có một hàm tạo rỗng và có một phương thức được gọi là doit() nhận một đối số String và trả về một String. Ngoài ra nó đảo ngược chuỗi.

Đây là mã của tôi:

URL url = new URL("file://C:/jtest/"); 
    URLClassLoader loader = new URLClassLoader(new URL[]{url}); 
    Class<?> cl = loader.loadClass("Foo"); 
    Constructor<?> cons = cl.getConstructor((Class[])null); 
    Object ins = cons.newInstance(new Object[]{}); 
    Method meth = cl.getDeclaredMethod("doit", String.class); 
    Object ret = meth.invoke(ins, new Object[]{"!dlroW olleH"}); 
    System.out.println((String)ret); 

Đúng như dự đoán in này "Hello World!". Tuy nhiên, phải mất khoảng 30 giây để hoàn tất. Tôi biết sự phản chiếu chậm, nhưng tôi mong đợi nó là 10 ms hoặc một cái gì đó.

Tôi đang sử dụng Eclipse với JRE 1.6.0_13 và tôi đang chạy Windows Vista.

Tôi đang làm gì sai ở đây?

Cảm ơn.

Chỉnh sửa: Tôi đã lược tả mã và tất cả thời gian của nó được sử dụng trong dòng thứ ba (loadClass()). Mọi thứ khác xảy ra ngay lập tức.

Chỉnh sửa: Tôi đã đặt mã trong vòng lặp; các chức năng chậm bằng cách nào đó được tối ưu hóa và mất 30 giây chỉ trên vòng đầu tiên.

Chỉnh sửa: Tôi đã tìm thấy giải pháp.

Thay vì:

URL url = new URL("file://C:/jtest/");

tôi đã thay đổi nó để:

URL url = new URL("file:/C:/jtest/");

Bây giờ nó hoạt động hoàn hảo. Tôi không biết tại sao nó hoạt động, nhưng tôi không thấy làm thế nào tôi (và 5 người khác) có thể đã bỏ lỡ điều đó. Bây giờ tôi cảm thấy câm ..

+1

loadClass trước tiên kiểm tra bộ nhớ cache để xem liệu lớp đã được tải chưa, nếu tôi nhớ chính xác. Điều đó sẽ giải thích tại sao nó không mất nhiều thời gian trong lần lặp thứ hai. –

+0

Là "Foo" thực sự trong một gói? Tải từ gói mặc định (không có gói) có thể có hiệu ứng lạ. Hãy thử chuyển sang foo.Foo. – flicken

+0

Thật thú vị ... URL mới ("tệp:/C:/jtest /"). GetPath() là/C:/jtest /. Tôi tự hỏi làm thế nào URLClassLoader diễn giải điều đó. –

Trả lời

5

Tại 30 giây, bạn sẽ có thể "profile" mã của bạn và xem chính xác nơi mà vấn đề nằm (trong tải của lớp? Trong việc tạo ra ví dụ? Trong nhìn lên phương pháp này? Vv?)

Kể từ khi nó mất 30 giây (và không phải cái gì nhỏ hơn nhiều, theo thứ tự 10ms hoặc hơn), bạn chỉ có thể sử dụng System.out.println(new Date()); giữa mỗi dòng mã của bạn.

Tôi nghi ngờ bạn sẽ tìm thấy đó là trình tải.loadClass (String) mất quá nhiều thời gian - và tôi nghi ngờ rằng bạn sẽ tìm thấy bạn có một classpath rất dài, hoặc một classpath bao gồm một tài nguyên mạng của một số loại.

+2

@unknown: trong trường hợp đó (và nếu bạn giải quyết được vấn đề), bạn nên đăng câu trả lời mà bạn biết là chính xác và chấp nhận câu trả lời đó. –

5

Kiểm tra đường dẫn lớp mặc định của bạn. Có lẽ nó đề cập đến một chia sẻ mạng không có sẵn hoặc một cái gì đó như thế.

+0

Tôi làm như thế nào? – Lucky

+0

echo% CLASSPATH% trong dấu nhắc lệnh –

+0

hoặc kiểm tra cài đặt trong Eclipse –

2

Không có gì sai với mã của bạn ... Tôi đã có thể biên dịch chương trình của bạn trong chưa đầy một giây. Tôi đang chạy java 1.6.11 trên Vista Business.

Có lẽ phương pháp public string doit(string arg) của bạn là những gì mất quá nhiều thời gian. Bạn có thể thử gọi nó mà không sử dụng sự phản chiếu để xem liệu nó có mất nhiều thời gian không? Hãy thử có doit() chỉ cần trả lại thông số bạn chuyển vào (thay vì đảo ngược các ký tự) để xem thuật toán đảo ngược của bạn có phải là những gì làm chậm nó không.

+0

Ông cho biết mất 30 giây để hoàn tất. Tôi cho rằng điều này có nghĩa là hoàn thành việc thực hiện, không phải để biên dịch. –

+0

Nó được biên soạn và chạy trong chưa đầy một giây. Đó là lý do tại sao tôi nói với anh ta để thử thực hiện nó với một thực hiện khác nhau của phương pháp doit() của mình. – Cuga

+0

doit() trả về ngay lập tức khi sử dụng mã không phản chiếu. – Lucky

3

Có thể khi bạn tạo cá thể, nó khiến nhiều lớp khác tải, một số trong đó có các trình khởi tạo tĩnh làm công cụ mất nhiều thời gian. Đặt mã này trong một vòng lặp và xem những gì tạo ra đối tượng tiếp theo chi phí.

Chỉnh sửa: Làm mát, dựa trên hồ sơ của bạn điều này nghe có vẻ như bạn đang gần gũi với nguyên nhân gốc rễ. Một điều cần xem xét là nếu bạn đang sử dụng thư viện có chi phí khởi động lớn. Tôi sử dụng iBatis để quản lý tương tác của chúng tôi với Oracle, và khi nó lần đầu tiên kích hoạt nó đọc trong một loạt các tệp XML và xử lý các mẫu truy vấn trong chúng. Có một sự chậm trễ đáng chú ý. Thật thú vị khi nghe những gì bạn tìm ra, nhưng bạn có thể quyết định chi phí một lần là có thể chấp nhận được.

2

Có thể cho bạn để đặt Foo trong CLASSPATH mặc định vì vậy bạn chỉ có thể sử dụng một cái gì đó như:

ClassLoaderTest.class.getClassLoader() 

, nơi ClassLoaderTest là lớp bạn đang chạy trong Hoặc, với điều kiện nếu bạn. không chạy trong ngữ cảnh tĩnh, sau đó:

this.getClass().getClassLoader()` 

Một trong hai cách này sẽ giúp bạn tiết kiệm ngay lập tức trình nạp lớp mới.

Nhưng tôi không biết nếu điều này thậm chí sẽ giúp bạn (bạn phải cấu hình), và phản ánh luôn luôn là đáng chú ý chậm hơn. Không có xung quanh đó. Tất nhiên, nó nên được sử dụng tối thiểu trong sản xuất, vì lý do này và các lý do khác.

EDIT: Vì loadClass đang chiếm hầu hết thời gian, có thể C: \ jtest bị lộn xộn. Bạn có thể thử đặt Foo.class một mình trong một thư mục và sử dụng nó làm URL. Tất nhiên, lý do nó nhanh hơn lần thứ hai là Foo đã được tải.

6

Để biết thông tin của bạn: Có thể hơi muộn cho bạn, nhưng tôi tình cờ gặp phải vấn đề tương tự và tìm thấy bài đăng này.

Có vẻ như // đang buộc tìm kiếm từ xa, nếu bạn chạy với -verbose: lớp có một UnknownHostException được tải để điều này phải được ném nội bộ trong khi tải lớp.

tôi thử như sau:

URL url = URL mới ("file: // localhost/C:/jtest /");

và công trình này (gần như) nhanh nhất là giải pháp cắt giảm duy nhất của bạn.

+0

Đã lưu tôi 4 phút chạy bộ và kéo tóc hàng giờ – MonoThreaded

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