2009-03-26 30 views
8

Tôi có một dự án Java Maven với khoảng 800 tệp nguồn (một số được tạo bởi javacc/JTB), việc này sẽ mất 25 phút để biên dịch với javac.Tại sao javac 1.5 chạy chậm như vậy so với trình biên dịch Eclipse?

Khi tôi thay đổi tệp pom.xml của mình để sử dụng trình biên dịch Eclipse, phải mất khoảng 30 giây để biên dịch.

Bất kỳ đề xuất nào về lý do tại sao javac (1.5) đang chạy quá chậm? (Tôi không muốn chuyển sang trình biên dịch Eclipse vĩnh viễn, vì plugin cho Maven có vẻ nhiều hơn một chút lỗi.)

Tôi có một trường hợp thử nghiệm dễ dàng tái tạo vấn đề. Đoạn mã sau tạo ra một số tệp nguồn trong gói mặc định. Nếu bạn cố gắng biên dịch ImplementingClass.java bằng javac, nó sẽ có vẻ tạm dừng trong một thời gian dài.

import java.io.File; 
import java.io.FileNotFoundException; 
import java.io.PrintStream; 

public class CodeGenerator 
{ 
    private final static String PATH = System.getProperty("java.io.tmpdir"); 
    private final static int NUM_TYPES = 1000; 

    public static void main(String[] args) throws FileNotFoundException 
    { 
     PrintStream interfacePs = new PrintStream(PATH + File.separator + "Interface.java"); 
     PrintStream abstractClassPs = new PrintStream(PATH + File.separator + "AbstractClass.java"); 
     PrintStream implementingClassPs = new PrintStream(PATH + File.separator + "ImplementingClass.java"); 
     interfacePs.println("public interface Interface<T> {"); 
     abstractClassPs.println("public abstract class AbstractClass<T> implements Interface<T> {"); 
     implementingClassPs.println("public class ImplementingClass extends AbstractClass<Object> {"); 

     for (int i=0; i<NUM_TYPES; i++) 
     { 
      String nodeName = "Node" + i; 
      PrintStream nodePs = new PrintStream(PATH + File.separator + nodeName + ".java"); 
      nodePs.printf("public class %s { }\n", nodeName); 
      nodePs.close(); 
      interfacePs.printf("void visit(%s node, T obj);%n", nodeName); 
      abstractClassPs.printf("public void visit(%s node, T obj) { System.out.println(obj.toString()); }%n", nodeName); 
     } 
     interfacePs.println("}"); 
     abstractClassPs.println("}"); 
     implementingClassPs.println("}"); 
     interfacePs.close(); 
     abstractClassPs.close(); 
     implementingClassPs.close(); 
    } 
} 
+1

Thử tạo SSCCE (http://sscce.org/) và gửi báo cáo lỗi với Sun (http://bugs.sun.com/). Đặc biệt là kể từ khi bạn đã giảm các vấn đề cho một trường hợp khá cụ thể. –

+0

Bạn đang sử dụng hệ điều hành nào? Đó là nhanh chóng cho tôi ... trên OS X. – TofuBeer

+0

Đây là trên Windows XP và Windows Server 2003 –

Trả lời

6

Bạn nhận được hành vi tương tự với JDK 1.6, bao gồm bản cập nhật 14, phiên bản 04, sử dụng G1 không thay đổi hành vi, (mặc dù G1 có vẻ hoạt động tốt).

Giám sát javac với jvisualvm, bãi chủ đề lặp đi lặp lại hiển thị các chủ đề chính dành rất nhiều thời gian trong

at com.sun.tools.javac.code.Types.isSubSignature(Types.java:1846) 
at com.sun.tools.javac.code.Symbol$MethodSymbol.overrides(Symbol.java:1108) 
at com.sun.tools.javac.code.Symbol$MethodSymbol.implementation(Symbol.java:1159) 
at com.sun.tools.javac.comp.Check.checkCompatibleConcretes(Check.java:1239) 
at com.sun.tools.javac.comp.Check.checkCompatibleSupertypes(Check.java:1567) 
at com.sun.tools.javac.comp.Attr.attribClassBody(Attr.java:2674) 
at com.sun.tools.javac.comp.Attr.attribClass(Attr.java:2628) 
at com.sun.tools.javac.comp.Attr.attribClass(Attr.java:2564) 
at com.sun.tools.javac.main.JavaCompiler.attribute(JavaCompiler.java:1036) 
at com.sun.tools.javac.main.JavaCompiler.compile2(JavaCompiler.java:765) 
at com.sun.tools.javac.main.JavaCompiler.compile(JavaCompiler.java:730) 
at com.sun.tools.javac.main.Main.compile(Main.java:353) 
at com.sun.tools.javac.main.Main.compile(Main.java:279) 
at com.sun.tools.javac.main.Main.compile(Main.java:270) 
at com.sun.tools.javac.Main.compile(Main.java:69) 
at com.sun.tools.javac.Main.main(Main.java:54) 

và khuấy qua một số lượng lớn các trường hợp sống ngắn của các lớp này:

com.sun.tools.javac.code.Types$Subst 
com.sun.tools.javac.util.List 
com.sun.tools.javac.code.Types$MethodType 

tôi nghi ngờ mã được chuyển qua com.sun.tools.javac.comp.Check.checkCompatibleConcretes so sánh từng phương pháp với mọi phương pháp khác

Phương thức đó là javadoc:

/** Check that a class does not inherit two concrete methods 
* with the same signature. 
*/ 

Có thể trình biên dịch của nhật thực không thực hiện việc kiểm tra đó hoặc không thực hiện theo cùng một cách.

0

Có lẽ bản dựng Eclipse chỉ biên dịch nguồn được sửa đổi. Điều gì sẽ xảy ra nếu bạn biên dịch nó trong nhật thực sau khi làm sạch?

+0

Tôi đã làm 'mvn clean' trước 'mvn install' trong cả hai trường hợp. –

1

Đối với trình biên dịch Sun, bạn đang khởi động toàn bộ quy trình JVM cho mỗi tệp bạn muốn biên dịch. Đối với trình biên dịch Eclipse, nó chỉ kết nối với một quy trình daemon. Tôi đề nghị thiết lập ngã ba thành sai, mặc dù nó vẫn có thể không được khá nhanh.

+0

Điều đó có tạo ra sự khác biệt 25 phút không? Tôi sẽ không nghĩ như vậy ... –

+0

25 phút/80 nguồn tệp = 18.75 giây mỗi javac. Có thể nếu cho mỗi tệp nguồn, nó phải tải một khối lượng các lọ/lớp. –

+0

Cảm ơn bạn đã đề xuất - Tôi đã thử nó, nhưng tiếc là nó không tạo sự khác biệt đáng chú ý trong thời gian biên dịch. –

2

Thực tế là bạn đang sử dụng nguồn tạo ra, sự khác biệt lớn về tốc độ và StackOverflowError có thể gợi ý rằng một (hoặc nhiều hơn) các tập tin của bạn có một số cấu trúc rằng javac parsers không đồng ý với.

Bạn có thể cố gắng biên dịch các tập hợp con của mã của bạn và xem liệu có một lớp/gói nào làm chậm quá trình đặc biệt (có thể là một trong các gói được tạo).

+0

Bây giờ tôi đã cố gắng tách dự án thành hai - 391 tệp được tạo bởi javacc/jtb và 373 được mã hóa bằng tay. Phần lớn thời gian được sử dụng để biên dịch các mã được viết tay (biên soạn những cái được tạo ra mất khoảng 18 giây) –

+0

Thú vị, tôi sẽ không đoán được điều đó. Tôi muốn chia nhỏ các tệp nguồn hơn nữa và tiếp tục cố gắng tìm hiểu xem một vài tệp có chịu trách nhiệm làm chậm tốc độ không. –

+0

Một gợi ý: chạy xây dựng của bạn bằng cách sử dụng "strace -eopen ant". Điều này sẽ in ra mỗi khi một tập tin được mở ra. Đợi tạm dừng trong luồng đầu ra khổng lồ đó và kiểm tra tên tệp cuối cùng được mở trước đó. Nên cung cấp cho bạn một gợi ý phong nha. –

5

Có thể trình biên dịch javac hoạt động gần với giới hạn heap (64MB hoặc hơn). Trong trường hợp đó, nó dành phần lớn thời gian trong bộ thu gom rác. Cung cấp cho trình biên dịch một đoạn bộ nhớ tốt, nói 256M hoặc 512M và xem liệu nó có chạy nhanh hơn không.

+0

Trừ khi được định cấu hình khác, trình biên dịch maven-plugin chạy javac trong quá trình. Một sửa chữa có thể cho simonn để thử sẽ được thiết lập biến môi trường MAVEN_OPTS để "-Xms128M Xmx512M" hay như vậy. Nếu plugin được định cấu hình fork = true, anh ta có thể sử dụng tham số meminitial và maxmem để kiểm soát điều này. – Barend

+0

Tôi đã thử chạy "javac -verbose -J-Xms512m -J-Xmx1024m ImplementingClass.java" và sự cố vẫn tiếp diễn. –

0

Tôi không biết làm thế nào maven gọi trình biên dịch nhưng số hiệu suất bạn đề cập rằng javac được thực hiện trong quá trình riêng của nó/VM như đã được đề xuất trong câu trả lời khác. Khi bắt đầu một quá trình/VM mới cho mỗi tập tin bạn biên dịch là rất tốn kém, bạn cần phải đảm bảo cấu hình trình biên dịch để sử dụng máy ảo mà bạn có thể có. Tôi biết ANT cung cấp, nhưng tôi đã không sử dụng maven bản thân mình. Với thực tế là nó là phổ biến tôi nghi ngờ rằng nó thiếu một tính năng quan trọng như vậy mặc dù.

0

Tôi nghĩ rằng một cái gì đó như sau đang xảy ra: Maven dĩa javac, quy trình JVM cho các bước riêng biệt trong vòng đời của nó: Maven Build Life-cycle

Eclipse thường chạy biên dịch của nó trong nền (Save), do đó bước sẽ được thêm vào giai đoạn biên dịch. Nếu có phụ thuộc đáng kể, đây là nơi bạn đang mất thông lượng.

Ngoài ra (tùy thuộc vào cấu hình mvn), mỗi phương pháp thử đều có JVM riêng. Vì đoạn thử nghiệm là một yêu cầu trước cho giai đoạn gói, có thể bạn đang mất thời gian thực hiện kiểm tra JUnit của mình (đặc biệt nếu chúng là các thử nghiệm chạy chậm). Đây chỉ là thủ phạm có khả năng nếu bạn có nhiều mã thử nghiệm trong cây nguồn của bạn.

Rất có thể tất cả, lớp học của bạn có số lượng tệp I/O đáng kể, vì vậy đó là một lĩnh vực cơ hội. Dường như vòng lặp của bạn đang thực thi 1000 lần cho mỗi sự kiện phát hiện tệp có nghĩa là 800 * 1000 = 800.000 sáng tạo PrintStream trong phần thân của vòng lặp.

7

Sun đã xác nhận với tôi bằng email rằng đây là lỗi mới (6827648 trong cơ sở dữ liệu lỗi của họ).

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