لماذا javac 1.5 تشغيل ببطء شديد مقارنة مع المترجم الكسوف؟

StackOverflow https://stackoverflow.com/questions/686545

  •  22-08-2019
  •  | 
  •  

سؤال

ولدي مشروع جافا مخضرم مع حوالي 800 الملفات المصدر (بعض الناتجة عن javacc / JTB) التي تتخذ جيدة 25 دقيقة ترجمة مع javac.

وعندما غيرت بلدي pom.xml على استخدام المترجم الكسوف، ويستغرق حوالي 30 ثانية لتجميع.

وأي اقتراحات لماذا javac (1.5) يعمل ببطء شديد؟ (أنا لا أريد أن التحول إلى المترجم الكسوف بشكل دائم، كما المساعد للمخضرم يبدو أكثر من عربة صغيرة).

ولدي حالة اختبار الذي يستنسخ المشكلة بسهولة. التعليمة البرمجية التالية يولد عددا من الملفات المصدر في الحزمة الافتراضي. إذا حاولت تجميع ImplementingClass.java مع javac، سوف يبدو إلى وقفة لفترة طويلة بشكل غير منتظم.

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();
    }
}
هل كانت مفيدة؟

المحلول

ويمكنك الحصول على نفس السلوك مع JDK 1.6، بما في ذلك تحديث 14، وبناء 04، وذلك باستخدام G1 لا يغير السلوك، (على الرغم من G1 يبدو أن تعمل بشكل جيد حقا).

وjavac رصد مع jvisualvm، مقالب موضوع المتكررة تظهر الرئيسية الكثير الإنفاق موضوع من الوقت في

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)

وومتماوج من خلال عدد كبير من الحالات قصيرة الأجل من هذه الفئات:

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

وأظن أن الكود هو متماوج من خلال com.sun.tools.javac.comp.Check.checkCompatibleConcretes مقارنة كل الأسلوب مع كل طريقة أخرى

وجافادوك هذا الأسلوب في:

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

قد يكون المترجم أن كسوف إما لا يتم تنفيذ هذا الاختيار، أو لا يتم تنفيذ ذلك في نفس الطريق.

نصائح أخرى

لقد أكد سون لي عن طريق البريد الإلكتروني أن هذا خطأ جديد ( 6827648 في قاعدة بيانات علة بهم).

ومن المحتمل أن يكون المترجم javac يعمل فاحصة على حد كومة لها (64MB أو نحو ذلك). في هذه الحالة، فإنه يقضي معظم الوقت في جمع القمامة. تعطي المترجم جزءا كبيرا من الذاكرة، ويقول 256M أو 512M ومعرفة ما اذا كان يعمل بشكل أسرع.

والحقيقة أن كنت تستخدم مصدر ولدت، و<م> ضخمة الفرق في السرعة وStackOverflowError قد تشير إلى أن واحدة (أو أكثر) من الملفات لديك بعض التركيبات التي موزعي javac لا توافق مع.

هل يمكن أن محاولة تجميع مجموعات فرعية فقط من التعليمات البرمجية الخاصة بك ومعرفة ما إذا كان أي فئة واحدة / حزمة يبطئ عملية خاصة (على الارجح واحدة من تلك المولدة).

لالمترجم الشمس كنت بدء عملية JVM كامل لكل الملف الذي ترغب في ترجمة. لمترجم الكسوف هو مجرد ربط عملية الخفي. أقترح وضع الشوكة إلى false، على الرغم من أنه لا يزال قد لا يكون تماما بالسرعة.

المصدر ولعل بناء الكسوف هو إلا تجميع تعديل. ماذا يحدث إذا ترجمة عليه في الكسوف بعد نظيفة؟

وأنا لا أعرف كيف يدعو مخضرم المترجم ولكن أرقام الأداء أذكر لكم أقترح أن يتم تنفيذ javac في معالجته الخاصة / VM كما اقترح بالفعل في إجابة أخرى. كما تبدأ عملية جديدة / VM لكل الملف الذي جمع مكلف للغاية تحتاج إلى التأكد من تكوين مترجم لاستخدام VM قد يكون لديك alreay. وأنا أعلم تقدم ANT ذلك، ولكن أنا لم تستخدم مخضرم نفسي. وبالنظر إلى أن أنها تحظى بشعبية أشك في أنها تفتقر إلى مثل هذه ميزة هامة بالرغم من ذلك.

وأعتقد أن هناك شيئا كما يلي يجري: مخضرم الشوك javac والعمليات JVM لخطوات منفصلة في دورة حياته: <لأ href = "http://maven.apache.org/guides/introduction/introduction-to -The-lifecycle.html "يختلط =" نوفولو noreferrer "> مخضرم بناء دورة الحياة

والكسوف يدير عادة الترجمة في الخلفية (على حفظ)، لذلك سوف تضاف هذه الخطوة إلى مرحلة الترجمة. إذا كان هناك تبعيات كبيرة، وهذا هو المكان الذي كنت فقدان الإنتاجية.

وبالإضافة إلى ذلك (اعتمادا على التكوين mvn) كل طريقة الاختبار يحصل JVM الخاصة به. منذ اختبار مرور هو قبل مسا إلى مرحلة الحزمة، فإنه من الممكن أن نخسر الوقت لإعدام اختبار أداة JUnit الخاص بك (وخاصة اذا كانا لا يزالان اختبارات تشغيل بطيئة). هذه ليست سوى الجاني المحتمل إذا كان لديك الكثير من رمز اختبار في شجرة المصدر.

وعلى الأرجح قبل كل شيء، صفك يفعل كميات كبيرة من الملف I / O، ذلك أن مساحة الفرصة. يبدو أن حلقة الخاص بك المنفذة 1000 مرة في الحدث اكتشاف الملف وهذا يعني 800 * 1000 = 800000 الإبداعات PrintStream في الجسم من الحلقة.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top