زمان اجرا Android (ART) زمان اجرا پیشفرض برای دستگاههای دارای Android نسخه 5.0 (سطح API 21) و بالاتر است. این زمان اجرا تعدادی ویژگی را ارائه می دهد که عملکرد و روان بودن پلتفرم و برنامه های اندروید را بهبود می بخشد. می توانید اطلاعات بیشتری در مورد ویژگی های جدید ART در معرفی ART بیابید.
با این حال، برخی از تکنیک هایی که روی Dalvik کار می کنند، روی ART کار نمی کنند. این سند به شما امکان میدهد هنگام انتقال یک برنامه موجود برای سازگاری با ART، مواردی را که باید تماشا کنید. اکثر برنامهها باید فقط هنگام اجرا با ART کار کنند.
رسیدگی به مسائل مربوط به جمع آوری زباله (GC).
تحت Dalvik، برنامهها اغلب فراخوانی صریح System.gc()
برای درخواست جمعآوری زباله (GC) مفید میدانند. این باید در مورد ART بسیار کمتر ضروری باشد، به خصوص اگر از جمع آوری زباله برای جلوگیری از وقوع نوع GC_FOR_ALLOC
یا کاهش تکه تکه شدن استفاده می کنید. با فراخوانی System.getProperty("java.vm.version")
می توانید بررسی کنید که کدام زمان اجرا در حال استفاده است. اگر ART در حال استفاده است، مقدار ویژگی "2.0.0"
یا بالاتر است.
ART از کلکتور کپی همزمان (CC) استفاده می کند که همزمان پشته جاوا را فشرده می کند. به همین دلیل، باید از استفاده از تکنیک هایی که با فشرده سازی GC ناسازگار هستند (مانند ذخیره اشاره گرها در داده های نمونه شی) اجتناب کنید. این به ویژه برای برنامه هایی که از رابط بومی جاوا (JNI) استفاده می کنند بسیار مهم است. برای اطلاعات بیشتر، به پیشگیری از مشکلات JNI مراجعه کنید.
پیشگیری از مسائل JNI
JNI ART تا حدودی سختگیرتر از Dalvik است. استفاده از حالت CheckJNI برای یافتن مشکلات رایج ایده خوبی است. اگر برنامه شما از کد C/C++ استفاده می کند، باید مقاله زیر را مرور کنید:
اشکال زدایی اندروید JNI با CheckJNI
بررسی کد JNI برای مشکلات جمع آوری زباله
گردآورنده کپی همزمان (CC) ممکن است اشیاء را در حافظه برای فشرده سازی حرکت دهد. اگر از کد C/C++ استفاده می کنید، عملیاتی را انجام ندهید که با فشرده سازی GC ناسازگار است. ما CheckJNI را برای شناسایی برخی مشکلات بالقوه (همانطور که در JNI Local Reference Changes in ICS توضیح داده شده است) تقویت کرده ایم.
یکی از مناطقی که به طور خاص باید مراقب آن بود، استفاده از توابع Get...ArrayElements()
و Release...ArrayElements()
است. در زمانهای اجرا با GC غیر فشرده، توابع Get...ArrayElements()
معمولاً یک مرجع به حافظه واقعی پشتیبان شی آرایه برمیگردانند. اگر تغییری در یکی از عناصر آرایه برگشتی ایجاد کنید، شی آرایه خودش تغییر می کند (و آرگومان های Release...ArrayElements()
معمولا نادیده گرفته می شوند. با این حال، اگر فشرده سازی GC در حال استفاده باشد، توابع Get...ArrayElements()
ممکن است یک کپی از حافظه را برگرداند. اگر هنگام استفاده از GC فشرده از مرجع استفاده نادرست کنید، این می تواند منجر به خراب شدن حافظه یا مشکلات دیگر شود. به عنوان مثال:
- اگر هر گونه تغییری در عناصر آرایه برگشتی ایجاد کردید، باید پس از اتمام کار، تابع
Release...ArrayElements()
مناسب را فراخوانی کنید تا مطمئن شوید که تغییراتی که ایجاد کرده اید به درستی در شی آرایه زیرین کپی شده است. - هنگامی که عناصر آرایه حافظه را آزاد می کنید، بسته به تغییراتی که ایجاد کرده اید، باید از حالت مناسب استفاده کنید:
- اگر هیچ تغییری در عناصر آرایه ایجاد نکردید، از حالت
JNI_ABORT
استفاده کنید، که حافظه را بدون کپی کردن تغییرات به شی آرایه زیرین آزاد می کند. - اگر تغییراتی در آرایه ایجاد کردید و دیگر به مرجع نیاز ندارید، از کد
0
استفاده کنید (که شی آرایه را به روز می کند و کپی حافظه را آزاد می کند). - اگر تغییراتی را در آرایه ای که می خواهید متعهد شوید ایجاد کرده اید و می خواهید کپی آرایه را نگه دارید، از
JNI_COMMIT
(که شی آرایه زیرین را به روز می کند و کپی را حفظ می کند) استفاده کنید.
- اگر هیچ تغییری در عناصر آرایه ایجاد نکردید، از حالت
- هنگامی که
Release...ArrayElements()
را فرا می خوانید، همان اشاره گر را که در ابتدا توسطGet...ArrayElements()
برگردانده شده بود، برگردانید. به عنوان مثال، افزایش نشانگر اصلی (برای اسکن عناصر آرایه برگشتی) و سپس ارسال نشانگر افزایشی بهRelease...ArrayElements()
امن نیست. عبور از این نشانگر اصلاح شده می تواند باعث آزاد شدن حافظه اشتباه و در نتیجه خراب شدن حافظه شود.
رسیدگی به خطا
JNI ART در تعدادی از مواردی که دالویک این کار را نمی کند، خطا می کند. (یک بار دیگر، می توانید با آزمایش با CheckJNI موارد بسیاری از این قبیل را بگیرید.)
برای مثال، اگر RegisterNatives
با متدی فراخوانی شود که وجود ندارد (شاید به این دلیل که متد توسط ابزاری مانند ProGuard حذف شده است)، ART اکنون NoSuchMethodError
را به درستی پرتاب می کند:
08-12 17:09:41.082 13823 13823 E AndroidRuntime: FATAL EXCEPTION: main 08-12 17:09:41.082 13823 13823 E AndroidRuntime: java.lang.NoSuchMethodError: no static or non-static method "Lcom/foo/Bar;.native_frob(Ljava/lang/String;)I" 08-12 17:09:41.082 13823 13823 E AndroidRuntime: at java.lang.Runtime.nativeLoad(Native Method) 08-12 17:09:41.082 13823 13823 E AndroidRuntime: at java.lang.Runtime.doLoad(Runtime.java:421) 08-12 17:09:41.082 13823 13823 E AndroidRuntime: at java.lang.Runtime.loadLibrary(Runtime.java:362) 08-12 17:09:41.082 13823 13823 E AndroidRuntime: at java.lang.System.loadLibrary(System.java:526)
اگر RegisterNatives
بدون هیچ متد فراخوانی شود، ART یک خطا (قابل مشاهده در logcat) را ثبت می کند:
W/art ( 1234): JNI RegisterNativeMethods: attempt to register 0 native methods for <classname>
علاوه بر این، توابع JNI GetFieldID()
و GetStaticFieldID()
اکنون به جای اینکه به سادگی null را برگردانند NoSuchFieldError
به درستی پرتاب می کنند. به طور مشابه، GetMethodID()
و GetStaticMethodID()
اکنون NoSuchMethodError
به درستی پرتاب می کنند. این می تواند منجر به شکست CheckJNI به دلیل استثناهای کنترل نشده یا استثناهایی که برای فراخواننده های جاوا کد بومی ایجاد می شود، شود. این امر اهمیت ویژه ای برای آزمایش برنامه های سازگار با ART با حالت CheckJNI می کند.
ART از کاربران متدهای JNI CallNonvirtual...Method()
(مانند CallNonvirtualVoidMethod()
) انتظار دارد که طبق مشخصات JNI از کلاس اعلان متد استفاده کنند، نه یک کلاس فرعی.
جلوگیری از مشکلات اندازه پشته
Dalvik دارای پشته های جداگانه برای کدهای بومی و جاوا بود، با اندازه پیش فرض پشته جاوا 32 کیلوبایت و اندازه پشته اصلی پیش فرض 1 مگابایت. ART یک پشته یکپارچه برای موقعیت بهتر دارد. به طور معمول، اندازه پشته ART Thread
باید تقریباً مشابه Dalvik باشد. با این حال، اگر به صراحت اندازههای پشته را تنظیم کنید، ممکن است لازم باشد آن مقادیر را برای برنامههای در حال اجرا در ART بازبینی کنید.
- در جاوا، فراخوانیهای سازنده
Thread
را بررسی کنید که اندازه پشته صریح را مشخص میکنند. برای مثال، اگرStackOverflowError
رخ داد، باید اندازه را افزایش دهید. - در C/C++، استفاده از
pthread_attr_setstack()
وpthread_attr_setstacksize()
برای رشته هایی که کد جاوا را نیز از طریق JNI اجرا می کنند، مرور کنید. در اینجا مثالی از خطای ثبت شده هنگام تلاش یک برنامه برای فراخوانی JNIAttachCurrentThread()
در زمانی که اندازه pthread خیلی کوچک است آورده شده است:F/art: art/runtime/thread.cc:435] Attempt to attach a thread with a too-small stack (16384 bytes)
تغییر مدل شی
Dalvik به اشتباه به کلاسهای فرعی اجازه داد تا روشهای بسته خصوصی را لغو کنند. ART در چنین مواردی هشدار می دهد:
Before Android 4.1, method void com.foo.Bar.quux() would have incorrectly overridden the package-private method in com.quux.Quux
اگر قصد دارید متد یک کلاس را در بسته دیگری لغو کنید، متد را public
یا protected
اعلام کنید.
اکنون Object
دارای فیلدهای خصوصی است. برنامههایی که فیلدهای سلسله مراتب کلاس خود را منعکس میکنند باید مراقب باشند که به فیلدهای Object
نگاه نکنند. برای مثال، اگر یک سلسله مراتب کلاس را به عنوان بخشی از یک چارچوب سریال سازی تکرار می کنید، زمان را متوقف کنید
Class.getSuperclass() == java.lang.Object.class
به جای ادامه دادن تا زمانی که متد null
را برگرداند.
پروکسی InvocationHandler.invoke()
اکنون اگر آرگومان به جای آرایه خالی وجود نداشته باشد null
دریافت می کند. این رفتار قبلاً مستند شده بود، اما به درستی در Dalvik استفاده نشده بود. نسخههای قبلی Mockito با این مشکل مواجه هستند، بنابراین هنگام آزمایش با ART از نسخه بهروز شده Mockito استفاده کنید.
رفع مشکلات کامپایل AOT
کامپایل جاوا Ahead-Of-Time (AOT) ART باید برای همه کدهای استاندارد جاوا کار کند. کامپایل توسط ابزار dex2oat
ART انجام می شود. اگر در زمان نصب با مشکلی در ارتباط با dex2oat
مواجه شدید، به ما اطلاع دهید (به گزارش مشکلات مراجعه کنید) تا بتوانیم در اسرع وقت آنها را برطرف کنیم. چند موضوع قابل توجه:
- ART در زمان نصب بایت کد دقیق تری نسبت به Dalvik انجام می دهد. کد تولید شده توسط ابزارهای ساخت اندروید باید خوب باشد. با این حال، برخی از ابزارهای پس پردازش (به ویژه ابزارهایی که مبهم سازی را انجام می دهند) ممکن است فایل های نامعتبری را تولید کنند که توسط Dalvik قابل تحمل است اما توسط ART رد شده است. ما با فروشندگان ابزار برای یافتن و رفع چنین مشکلاتی کار کرده ایم. در بسیاری از موارد، دریافت آخرین نسخه ابزارهای خود و بازسازی فایل های DEX می تواند این مشکلات را برطرف کند.
- برخی از مشکلات معمولی که توسط تأیید کننده ART پرچم گذاری می شوند عبارتند از:
- جریان کنترل نامعتبر
-
monitorenter
نامتعادل /monitorexit
- اندازه لیست نوع پارامتر با طول 0
- برخی از برنامه ها به فرمت فایل
.odex
نصب شده در/system/framework
،/data/dalvik-cache
یا در فهرست خروجی بهینه شدهDexClassLoader
وابستگی دارند. این فایل ها اکنون فایل های ELF هستند و فرم توسعه یافته فایل های DEX نیستند. در حالی که ART سعی می کند از قوانین نامگذاری و قفل کردن مشابه Dalvik پیروی کند، برنامه ها نباید به فرمت فایل وابسته باشند. قالب ممکن است بدون اطلاع قبلی تغییر کند.توجه: در اندروید 8.0 (سطح API 26) و بالاتر، فهرست خروجی بهینه شده
DexClassLoader
منسوخ شده است. برای اطلاعات بیشتر، به مستندات سازندهDexClassLoader()
مراجعه کنید.
گزارش مشکلات
اگر با مشکلاتی مواجه شدید که به دلیل مشکلات برنامه JNI نیست، آنها را از طریق ردیاب مشکل پروژه منبع باز Android در https://code.google.com/p/android/issues/list گزارش دهید. در صورت موجود بودن "adb bugreport"
و پیوندی به برنامه در فروشگاه Google Play اضافه کنید. در غیر این صورت، در صورت امکان، یک APK که مشکل را بازتولید می کند، پیوست کنید. توجه داشته باشید که مشکلات (از جمله پیوست ها) به صورت عمومی قابل مشاهده هستند.