حول بناء JDK 8 على Ubuntu ، جودة كود Hotspot ، ولماذا فشل كل ذلك في C ++

كنت أرغب في النوم اليوم ، لكنها فشلت مرة أخرى. ظهرت رسالة في Telegram مفادها أن شخصًا ما لن يذهب إلى Java ... واستيقظنا فقط بعد بضع ساعات ، متعبًا وسعيدًا.




من يمكنه استخدام هذا المنشور؟ نعم ، ربما لأي شخص ما عدا أولئك الذين يجمعون JDK8 أو يحبون قراءة فظائع الكابوس. بشكل عام ، حذرتك ، أغلق المقال على وجه السرعة.

ثلاث مشاكل:


  • لن يحضر ( المستوى الأول )
    جزء ممل للغاية للتخطي. مطلوب فقط لأولئك الذين يريدون استعادة تاريخ الأحداث بالكامل ؛
  • لن يحضر ( المستوى الثاني )
    إنه أكثر إثارة للاهتمام نظرًا لوجود بعض الأخطاء النموذجية ، استحضار الأرواح ، تجبير الأرواح ، وهو BSD أفضل من GNU / Linux ولماذا يستحق التحول إلى إصدارات جديدة من JDK.
  • حتى لو كانت ستنخفض
    أكثر إثارة للاهتمام. Yahuuu ، سقطت JVM في القشرة ، فلنركلها!

تحت القطة يظهر حل مفصل للمشاكل ، مع أفكار جانبية مختلفة عن الحياة.


سيكون هناك الكثير من C ++ ، لن يكون هناك كود Java على الإطلاق. أي عازف في النهاية يبدأ في الكتابة فقط في C ++ ...


لن


يعرف من بنى Java مرة واحدة على الأقل أنه يبدو مثل هذا:


hg clone http://hg.openjdk.java.net/jdk8u/jdk8u cd jdk8u sh ./get_source.sh sh ./configure \ --with-debug-level=fastdebug \ --with-target-bits=64 \ --with-native-debug-symbols=internal \ --with-boot-jdk=/home/me/opt/jdk1.8.0_161 make images 

(يُسمى جميع المستخدمين ببساطة "أنا" ، بحيث يمكنك منح الجهاز الظاهري لأي شخص في أي وقت وعدم إنشاء رفض من استخدام اسم المستخدم الخاص بك)


المشكلة بالطبع هي أن هذا لا يعمل. وبطريقة ساخرة إلى حد ما.



مستوى الغوص الأول


دعنا نحاول تشغيل:


 /home/me/git/jdk8u/hotspot/src/os/linux/vm/os_linux.inline.hpp:127:18: warning: 'int readdir_r(DIR*, dirent*, dirent**)' is deprecated [-Wdeprecated-declarations] if((status = ::readdir_r(dirp, dbuf, &p)) != 0) { ^~~~~~~~~ 

أولاً ، لكي تفهم ، قمت بتثبيت هذا:


 $ g++ --version g++ (Ubuntu 7.3.0-16ubuntu3) 7.3.0 Copyright (C) 2017 Free Software Foundation, Inc. 

المترجم ليس هو النضارة الأولى ، وليس 8.2 ، ولكن يجب أن يعمل هذا أيضًا.


يحب مطورو C ++ اختبار البرنامج فقط على إصدار المترجم الذي قاموا بتثبيته. عادة ما تنتهي الرغبة في الاختبار على منصات مختلفة في مكان ما في المنطقة من الفرق بين دول مجلس التعاون الخليجي و clang بشكل عام. لذلك ، من الطبيعي أن يتم تشغيل -Werror لأول مرة ("تعامل مع التحذيرات على أنها أخطاء") ثم كتابة الشفرة التي تعتبر في جميع الإصدارات الأخرى vorings.


هذه مشكلة معروفة ، ومن الواضح كيفية حلها. تحتاج إلى تعيين متغير البيئة الخاص بك CXX_FLAGS ، لتعيين المستوى الصحيح من الأخطاء.


 export CXX_FLAGS=-Wno-error=deprecated-declarations -Wno-error-deprecated-declarations 

ثم نرى ما هو رائع:


 Ignoring CXXFLAGS found in environment. Use --with-extra-cxxflags 

حسنًا ، قم ببناء النظام ، كل ما تريد! نستبدل التكوين بهذا:


 hg clone http://hg.openjdk.java.net/jdk8u/jdk8u cd jdk8u sh ./configure \ --with-extra-cflags='-Wno-cpp -Wno-error=deprecated-declarations' \ --with-extra-cxxflags='-Wno-cpp -Wno-error=deprecated-declarations' \ --with-debug-level=fastdebug \ --with-target-bits=64 \ --with-native-debug-symbols=internal \ --with-boot-jdk=/home/me/opt/jdk1.8.0_161 make images 

ويظل الخطأ كما هو!
ننتقل إلى المدفعية الثقيلة: شفرة المصدر.


 grep -rl "Werror" . 

تقع كمية كبيرة من أي قبعة يتم إنشاؤها تلقائيًا ، من بينها لمحات من ملفات ذات معنى:


 ./common/autoconf/flags.m4 ./hotspot/make/bsd/makefiles/gcc.make ./hotspot/make/solaris/makefiles/gcc.make ./hotspot/make/aix/makefiles/xlc.make 

في flags.m4 نجد بسهولة الرسالة السابقة حول "تجاهل CXXFLAGS" والعلم الأكثر نضجًا CCXX_FLGS (نعم ، CCXX_FLGS C) ، والذي يعمل فورًا بدلاً من CFLAGS بدلاً من XX_FLAGS . ملائم! هناك حقيقتان مثيرتان للاهتمام:


  • لا يتم تمرير هذه العلامة من خلال معلمات التكوين ؛
  • في القيمة الافتراضية ذات مغزى ومريبة بشكل مشابه لهذه المعلمات:

  # Setup compiler/platform specific flags to CFLAGS_JDK, # CXXFLAGS_JDK and CCXXFLAGS_JDK (common to C and CXX?) if test "x$TOOLCHAIN_TYPE" = xgcc; then # these options are used for both C and C++ compiles CCXXFLAGS_JDK="$CCXXFLAGS $CCXXFLAGS_JDK -Wall -Wno-parentheses -Wextra -Wno-unused -Wno-unused-parameter -Wformat=2 \ -pipe -D_GNU_SOURCE -D_REENTRANT -D_LARGEFILE64_SOURCE" 

يبدو هذا السؤال جيدًا جدًا في التعليقات - ولكن ما هي العلامات الشائعة؟ صحيح؟


لن نلعب الديموقراطية والشفرة الصلبة الاستبدادية هناك - ("لا تظهر أي أخطاء"):


  CCXXFLAGS_JDK="$CCXXFLAGS $CCXXFLAGS_JDK -w -ffreestanding -fno-builtin -Wno-parentheses -Wno-unused -Wno-unused-parameter -Wformat=2 \ 

و - هتاف! - أول خطأ نمر به. لم تعد تقوم بالإبلاغ ، وبشكل عام كل شيء على ما يرام. يبدو.



مستوى الغوص الثاني


لكنها الآن تقع في كومة من أماكن جديدة أخرى!


اتضح أن عملنا -w ، ولكن لم يتم توجيهه إلى جميع أجزاء الجمعية. نقرأ بعناية ملفات makefiles ولا نفهم كيف يمكن إعادة توجيه هذه المعلمة على الإطلاق. حقا نسيت عنه؟


بمعرفة سؤال Google الصحيح ("لماذا لا يصل cxx إلى الإصدار؟!") ، نصل بسرعة إلى صفحة الخطأ بقول "تكوين - مع - إضافي - cxxflags لا يؤثر على نقطة الاتصال" ( JDK-8156967 ).


الوعد الذي سيتم إصلاحه في JDK 12. ربما. رائع - لا يتم استخدام معلمة البناء الأكثر أهمية في التجميع!


الفكرة الأولى هي ، حسنا ، دعونا نشمر عن سواعدنا ونصلح الأخطاء!


الخطأ 1.xn [12]


 dependencies.cpp: In function 'static void Dependencies::write_dependency_to(xmlStream*, Dependencies::DepType, GrowableArray<Dependencies::DepArgument>*, Klass*)': dependencies.cpp:498:6: error: '%d' directive writing between 1 and 10 bytes into a region of size 9 [-Werror=format-overflow=] void Dependencies::write_dependency_to(xmlStream* xtty, ^~~~~~~~~~~~ dependencies.cpp:498:6: note: directive argument in the range [0, 2147483647] 

حسنًا ، ربما نحتاج إلى توسيع المنطقة. مائة جنيه ، قام أحدهم بحساب المخزن المؤقت بالنقر فوق "أنا محظوظ!" في جوجل.


ولكن كيف تفهم كم تحتاج؟ هناك نوع آخر من التحسين أدناه:


 stdio2.h:34:43: note: '__builtin___sprintf_chk' output between 3 and 12 bytes into a destination of size 10 __bos (__s), __fmt, __va_arg_pack ()); 

يبدو الموضع 12 شيئًا ذا قيمة ، حيث يمكنك الآن اختراق المصدر بأقدام متسخة.


نتسلق إلى dependencies.cpp . cpp ونلاحظ الصورة التالية:


 DepArgument arg = args->at(j); if (j == 1) { if (arg.is_oop()) { xtty->object("x", arg.oop_value()); } else { xtty->object("x", arg.metadata_value()); } } else { char xn[10]; sprintf(xn, "x%d", j); if (arg.is_oop()) { xtty->object(xn, arg.oop_value()); } else { xtty->object(xn, arg.metadata_value()); } } 

انتبه إلى الخط الإشكالي:


 char xn[10]; sprintf(xn, "x%d", j); 

نغير 10 إلى 12 ، نعيد تجميع و ... الجمعية قد اختفت!


لكن هل أنا الوحيد ذكي جدًا وأصلح الخلل في كل العصور؟ لا شك ، نحن نجري مرة أخرى محرك megapatch إلى Google: char xn[12];


ونرى ... نعم ، هذا صحيح. الخطأ JDK-8184309 ، المحظور من قبل فلاديمير إيفانوف ، يحتوي على نفس الإصلاح بالضبط.


ولكن خلاصة القول هي أنه يتم إصلاحه فقط في JDK 10 ولا يتم إرجاع nifiga إلى jdk8u. هذا هو السؤال لماذا هناك حاجة إلى إصدارات جديدة من جافا.


خطأ 2. strcmp


 fprofiler.cpp: In member function 'void ThreadProfiler::vm_update(TickPosition)': /home/me/git/jdk8ut/hotspot/src/share/vm/runtime/fprofiler.cpp:638:56: error: argument 1 null where non-null expected [-Werror=nonnull] bool vm_match(const char* name) const { return strcmp(name, _name) == 0; } 

تدرس من قبل التجربة المريرة السابقة ، نذهب على الفور لرؤية ما هو موجود في هذا المكان في JDK 11. و ... هذا الملف غير موجود. وقد خضع هيكل الدليل أيضًا لبعض عمليات إعادة الهيكلة.


ولكن لا يمكنك الابتعاد عنا!


أي عازف جحاف يكون بخيل الأرواح في روحه ، وربما حتى مقبرة. لذلك ، سيكون هناك الآن قهر في العمل!


تحتاج أولاً إلى مناشدة روح الموتى ومعرفة متى مات:


 $ hg log --template "File(s) deleted in rev {rev}: {file_dels % '\n {file}'}\n\n" -r 'removes("**/fprofiler.cpp")' File(s) deleted in rev 47106: hotspot/src/share/vm/runtime/fprofiler.cpp hotspot/src/share/vm/runtime/fprofiler.hpp hotspot/test/runtime/MinimalVM/Xprof.java 

الآن تحتاج إلى معرفة سبب وفاته:


 hg log -r 47106 changeset: 47106:bed18a111b90 parent: 47104:6bdc0c9c44af user: gziemski date: Thu Aug 31 20:26:53 2017 -0500 summary: 8173715: Remove FlatProfiler 

لذا ، لدينا قاتل: gziemski . دعنا نكتشف سبب مسمر هذا الملف المؤسف.


للقيام بذلك ، انتقل إلى الدهون في التذكرة المحددة في ملخص الالتزام. هذا هو JDK-8173715 :


إزالة FlatProfiler:
نفترض أن هذه التكنولوجيا لم تعد قيد الاستخدام وأنها مصدر لمسح الجذر لـ GC.


لشيه مكرر. في الواقع ، نحن مدعوون الآن لإصلاح الجثة حتى يستمر البناء. الذي تحلل كثيرا لدرجة أن زملائنا مستحضر الأرواح من OpenJDK تخلى عنه.


فلنقم بإحياء القتيل ونحاول أن نسأله عما تذكره آخر مرة. لقد مات بالفعل في المراجعة 47106 ، مما يعني أن هناك واحدًا أقل في المراجعة - هذه "ثانية قبل":


 hg cat "~/git/jdk11/hotspot/src/share/vm/runtime/fprofiler.cpp" -r 47105 > ~/tmp/fprofiler_new.cpp cp ~/git/jdk8u/hotspot/src/share/vm/runtime/fprofiler.cpp ~/tmp/fprofiler_old.cpp cd ~/tmp diff fprofiler_old.cpp fprofiler_new.cpp 

لسوء الحظ ، لا شيء على الإطلاق فيما يتعلق return strcmp(name, _name) == 0; في فرق لا. توفي المريض من ضربة بأداة حادة غير حادة (فائدة rm) ، ولكن في وقت الوفاة كان بالفعل مريضًا بشكل نهائي.


دعونا نتعمق في جوهر الخطأ.


إليك ما يريد مؤلف الشفرة إخبارنا به:


  const char *name() const { return _name; } bool is_compiled() const { return true; } bool vm_match(const char* name) const { return strcmp(name, _name) == 0; } 

الآن القليل من الفلسفة.


المعيار C11 في البند 7.1.4 ، "استخدام وظائف المكتبة" ، ينص صراحة على ما يلي:


تنطبق كل من العبارات التالية ما لم ينص صراحة على خلاف ذلك في الأوصاف التفصيلية التي تلي: إذا كان لوسيطة دالة قيمة غير صالحة (مثل [...] مؤشر فارغ [...]) [...] ، السلوك غير محدد.

أي أن السؤال كله الآن هو ما إذا كان هناك بعض "صراحة خلاف ذلك" . لا شيء من هذا النوع مكتوب في وصف strcmp في القسم 7.24.4 ، وليس لدي أي أقسام أخرى لك.


أي لدينا سلوك غير محدد هنا.


بالطبع ، يمكنك أخذ وإعادة كتابة هذا الجزء من التعليمات البرمجية ، وتحيط به مع التحقق. لكنني لست متأكدًا تمامًا من أنني أفهم بشكل صحيح منطق الأشخاص الذين يستخدمون UB حيث لا ينبغي أن يكون. على سبيل المثال ، تقوم بعض الأنظمة بتوليد SIGSERV لعدم الإشارة إلى أي شيء ، ويمكن لمحبي الاختراق الاستفادة منه ، ولكن هذا السلوك ليس إلزاميًا وقد يبدأ في نظام أساسي آخر.


نعم ، بالطبع ، سيقول شخص ما أنك أحمق لنفسك ، وأنك تستخدم GCC 7.3 ، ولكن في GCC 4 كان كل شيء قد تجمع. لكن سلوك غير محدد! = غير محدد! = تم تعريف التنفيذ. يمكن وضع هذا لآخر اثنين للعمل في المترجم القديم. وكان UB في الإصدار السادس UB.


باختصار ، شعرت بالحزن التام من هذا السؤال الفلسفي المعقد (هل يجب أن أدخل في الكود مع افتراضاتي) عندما أدركت فجأة أنه يمكن أن يكون مختلفًا.


هناك طريقة أخرى


كما تعلم ، دائمًا ما يذهب الأبطال الجيدين.


حتى إذا تجاهلنا فلسفتنا حول UB ، هناك قدر لا يصدق من المشاكل هناك. ليس حقيقة أنه يمكن إصلاحها حتى الصباح. ليس حقيقة أنني لا أستطيع فعل ذلك بيدي ملتوية. والأقل من ذلك هو حقيقة أن هذا سيتم قبوله في المنبع: كان التصحيح الأخير في jdk8u منذ 6 أسابيع ، وكان هذا هو الدمج العالمي للعلامة الجديدة.


فقط تخيل أن الرمز أعلاه مكتوب بشكل صحيح بالفعل. كل ما يقف بيننا وبين تنفيذه هو تحذير ، كان يُنظر إليه على أنه خطأ بسبب خلل في نظام البناء. لكن يمكننا بناء نظام بناء.


قال Witcher Geralt of Rivia ذات مرة:


قال الشر بشكل خطير وهو يستيقظ: "الشر شرير ، ستريغوبور". - أصغر وأكبر ومتوسط ​​- كل شيء هو نفسه ، والنسب تعسفية ، والحدود غير واضحة. أنا لست ناسكًا مقدسًا ، ولم أفعل شيئًا واحدًا جيدًا في حياتي. ولكن إذا كان عليك الاختيار بين شر وآخر ، فأفضل عدم الاختيار على الإطلاق.

- Zło to zło، Stregoborze - rzekł poważnie wiedźmin wstając. - Mniejsze ، większe ، średnie ، wszystko jedno ، proporcje są umowne a granice zatarte. Nie jestem świątobliwym pustelnikiem، nie samo dobro czyniłem w życiu. Ale jeżeli mam wybierać pomiędzy jednym złem a drugim ، to wolę nie wybierać wcale.

هذا اقتباس من The Last Wish ، قصة تسمى Lesser Evil. نعلم جميعًا أن Geralt لم يتمكن أبدًا من لعب دور شخصية محايدة حقًا ، وحتى مات بسبب سلوك لطيف فوضوي كلاسيكي آخر.


لذا دعنا نظهر عرضًا سريعًا لأقل شرًا. دعنا نذهب في نظام البناء.


في البداية ، رأينا بالفعل هذا العادم:


 grep -rl "Werror" . ./common/autoconf/flags.m4 ./hotspot/make/linux/makefiles/gcc.make ./hotspot/make/bsd/makefiles/gcc.make ./hotspot/make/solaris/makefiles/gcc.make ./hotspot/make/aix/makefiles/xlc.make 

بمقارنة هذين الملفين ، كسرت وجهي بالكامل بجهد الوجه وأدركت الفرق في ثقافة النظامين الأساسيين:


BSD هي قصة عن الحرية والاختيار:


 # Compiler warnings are treated as errors ifneq ($(COMPILER_WARNINGS_FATAL),false) WARNINGS_ARE_ERRORS = -Werror endif 

غنو / لينكس نظام استبدادي مستبد:


 # Compiler warnings are treated as errors WARNINGS_ARE_ERRORS = -Werror 

حسنًا ، ستتم إعادة توجيهه إلى XX_FLAGS عبر XX_FLAGS ، ولا يؤخذ هذا المتغير في الاعتبار عند حساب WARNINGS_ARE_ERRORS ! في بناء غنو / لينكس ، ليس لدينا خيار سوى متابعة الإعدادات الافتراضية التي تم إطلاقها من الأعلى.


حسنًا ، أو يمكنك تسهيل الأمر وتغيير قيمة WARNINGS_ARE_ERRORS إلى قيمة قصيرة ، ولكن ليس أقل قوة. كيف تحب ذلك ، إيلون ماسك؟


كما كنت قد خمنت ، هذا يحل مشكلة البناء هذه تمامًا.


عندما يتم تجميع الكود ، سترى مجموعة من المشاكل الغريبة التي تبدو مروعة تحلق في الماضي. في بعض الأحيان كان الأمر مخيفًا لدرجة أنني كنت أرغب حقًا في الضغط على ctrl + C ومحاولة معرفة ذلك. ولكن لا ، لا يمكنك ، لا يمكنك ...


يبدو أن كل شيء تجمع ولم يجلب أي مشاكل إضافية. على الرغم من أنني بالطبع لم أجرؤ على بدء الاختبار. مع ذلك ، ليلا ، تبدأ عيني بالالتصاق معًا ، وبطريقة ما لا أريد الذهاب إلى الملاذ الأخير - أربع علب طاقة من الثلاجة.



يقع في القشرة


لقد مرت الجمعية ، تم إنشاء الملفات التنفيذية ، نحن عظماء.


وهكذا وصلنا إلى خط النهاية. أو لم تأت؟


يقع مجلسنا على النحو التالي:


 export JAVA_HOME=~/git/jdk8u/build/linux-x86_64-normal-server-fastdebug/jdk export PATH=$JAVA_HOME/bin:$PATH 

عند محاولة تشغيل java القابل للتنفيذ ، فإنه يتعطل على الفور. بالنسبة لأولئك الذين ليسوا على دراية - يبدو شيء مثل هذا:




في الوقت نفسه ، لدى أليكس ديبيان 9.5 ، ولدي أوبونتو. نسختان مختلفتان من دول مجلس التعاون الخليجي ، قشورتان مختلفتان. لدي مقالب بريئة مع التصحيح strcmp وعدد قليل من الأماكن الأخرى ، أليكس لا. ما هي المشكلة؟


هذه القصة تستحق قصة منفصلة ، ولكن دعنا ننتقل مباشرة إلى الاستنتاجات الجافة ، وإلا فلن أضيف هذه المشاركة أبدًا.


تكمن المشكلة في أن المذنبين المفضلين لدينا C ++ استخدموا مرة أخرى سلوكًا غير محدد.


(علاوة على ذلك ، حيث يعتمد بطريقة ما غير معروفة على تنفيذ المترجم. ومع ذلك ، يجب أن نتذكر أن UB هو دائمًا UB ، حتى على نسخة معروفة من المترجم فمن المستحيل وضعها عليه)


في مكان واحد ننتقل إلى حقل فئة غير مصممة هناك ، وكل شيء ينكسر. لا تسأل كيف حدث كل شيء معقد.


من الصعب جدًا على javista أن يتخيل كيف يمكن للمرء أن يتحول إلى فئة غير مكتملة البناء ، إلا عن طريق إصدار رابط لها مباشرة من المنشئ. لحسن الحظ ، يمكن للغة C ++ الرائعة أن تفعل كل شيء أو كل شيء تقريبًا. سأكتب مثالًا برمز زائف معين:


 class A { A() { _b.Show(); } private: static B _b; }; A a; BA::_b; int main() { } 

هل لديك تصحيح لطيف!


إذا نظرت إلى C ++ 98 [class.cdtor]:


بالنسبة لكائن من نوع فئة غير POD ... قبل أن يبدأ المنشئ في التنفيذ ... تشير الإشارة إلى أي عضو غير ثابت أو فئة أساسية للكائن إلى سلوك غير محدد

بدءًا من GCC لبعض الإصدارات (ولدي 7.3) ، ظهر تحسين "القضاء على المخزن الميت مدى الحياة" ، والذي يعتقد أننا نشير إلى كائن فقط خلال فترة حياته ، وكل شيء يسعل خارج وقت الحياة.


الحل هو تعطيل التحسينات الجديدة والعودة كما كانت في دول مجلس التعاون الخليجي القديمة:


 CFLAGS += -fno-strict-aliasing -fno-lifetime-dse -fno-delete-null-pointer-checks 

هناك نقاش حول هذا هنا .
لسبب ما ، قرر المشاركون في المناقشة أن هذا لن يتم تضمينه في المنبع. ولكن لا يزال عليك محاولة إرساله.


أضف هذه الخيارات إلى ./hotspot/make/linux/makefiles/gcc.make ، ./hotspot/make/linux/makefiles/gcc.make تجميع كل شيء مرة أخرى ./hotspot/make/linux/makefiles/gcc.make الخطوط العزيزة:


 t$ ~/git/jdk8u/build/linux-x86_64-normal-server-fastdebug/jdk/bin/java -version openjdk version "1.8.0-internal-fastdebug" OpenJDK Runtime Environment (build 1.8.0-internal-fastdebug-me_2018_09_10_08_14-b00) OpenJDK 64-Bit Server VM (build 25.71-b00-fastdebug, mixed mode) 

الخلاصة


ربما ظننت أن الاستنتاج سيكون: "جافا هي نوع من الجحيم ، هناك القمامة في الكود ، لا يوجد دعم ، كل شيء سيء."


الأمر ليس كذلك! على العكس من ذلك ، تُظهر الأمثلة أعلاه الشر الرهيب الذي يمنعنا عنه أصدقاؤنا ، مستحضر الأرواح من OpenJDK.


وعلى الرغم من حقيقة أنه يجب عليهم العيش واستخدام C ++ ، يرتعدون مع كل UB ويغيرون إصدار المترجم ويتعلموا التفاصيل الدقيقة للمنصات ، فإن كود المستخدم النهائي في Java مستقر بجنون ، وعلى الإصدارات المنشورة على مواقع الويب الرسمية لشركات مثل Azul ، بالكاد يمكن لـ Red Hat و Oracle مواجهة القشرة في حالة بسيطة.


الشيء المحزن الوحيد ، على الأرجح ، أنه من غير المحتمل أن يتم قبول الأخطاء التي تم العثور عليها في jdk8u. لقد أخذنا JDK 8 ببساطة لأنه من السهل علينا تصحيحه هنا والآن ، وعلينا أن نتعامل مع JDK 11. ومع ذلك ، لاستخدام JDK 8 في 2018 هو IMHO ، فهذه ممارسة سيئة للغاية ، ونحن لا نقوم بذلك من حياة جيدة. ربما تتحسن حياتنا في المستقبل ، وسوف تقرأ العديد من القصص المذهلة من عالم JDK 11 و JDK 12.


شكرا لاهتمامكم بمثل هذا النص الممل بدون صور :-)


دقيقة من الدعاية. سيعقد مؤتمر Joker 2018 قريبًا جدًا ، حيث سيكون هناك العديد من المتخصصين البارزين في Java و JVM. عرض القائمة الكاملة للمتحدثين والتقارير على الموقع الرسمي . سأكون هناك أيضًا ، سيكون من الممكن أن تلتقي وتطحن مدى الحياة و OpenJDK.

Source: https://habr.com/ru/post/ar422861/


All Articles