اولین سوالی که اکثر توسعه دهندگان جاوا دارند این است که مدیریت حافظه توسط J2ObjC چگونه پیاده سازی می شود، زیرا جاوا جمع آوری زباله دارد و Objective-C به طور پیش فرض ندارد. آنچه iOS دارد دو روش مدیریت حافظه است: شمارش مرجع و شمارش خودکار مرجع (ARC).
J2ObjC بسته به روش انتخاب شده، کدهای مدیریت حافظه متفاوتی تولید می کند. برای تولید کدی که از ARC استفاده می کند، با گزینه -use-arc
ترجمه کنید. به طور پیش فرض از شمارش منابع دستی استفاده می کند.
شمارش مراجع
روش شمارش مرجع مالکیت شی را واضح می کند. یک متد زمانی که یک شی را ایجاد می کند مالک آن است، تا زمانی که آن شی را آزاد کند. هنگام دریافت یک شی از متد دیگر، متد دریافت کننده آن شی را در صورتی که پس از بازگشت متد نیاز به ارجاع داشته باشد، حفظ می کند. وقتی روشی دیگر نیازی به ارجاع به یک شی ندارد، باید آن را آزاد کند. هنگامی که شمارش حفظ یک شی صفر باشد، حافظه آن آزاد می شود و شی دیگر معتبر نیست. هنگامی که اشیاء آزاد می شوند، متد ()deloc آنها فراخوانی می شود تا مالکیت متغیرهای نمونه آنها را آزاد کند.
یکی از مشکلات این تکنیک نحوه انتقال مالکیت یک شی است. برای مثال، ممکن است یک متد کارخانه ای برای ایجاد یک شیء فراخوانی شود. اگر متد کارخانه قبل از بازگرداندن شیء را آزاد کند (از آنجایی که دیگر نمی خواهد مالک شیء باشد)، آن شیء قبل از اینکه متد فراخوان بتواند آن را حفظ کند آزاد می شود.
برای انتقال مالکیت یک شی، یک متد یک پیام آزادسازی خودکار (به جای پیام انتشار) برای آن ارسال می کند که پیام انتشار را به تعویق می اندازد. این به روش کارخانه اجازه می دهد تا یک شی را ایجاد کند که باید برگردانده شود، و بدون بی اعتبار کردن شی، مالکیت آن را رها می کند. در فواصل زمانی منظم (مانند پس از هر تکرار حلقه رویداد در یک برنامه iOS)، استخر آزادسازی خودکار "تخلیه میشود"، به این معنی که همه اشیاء موجود در آن استخر پیامهای انتشار معوق ارسال میشوند. هر جسمی که تعداد نگهداری آنها به صفر برسد به طور معمول آزاد می شوند.
از آنجایی که بار مدیریت حافظه بر عهده توسعه دهنده است، به راحتی می توان حافظه را با روش شمارش مرجع لو داد. با این حال، اپل بهترین روشها را برای به حداقل رساندن این مشکل توصیه میکند، که J2ObjC پیادهسازی میکند.
همچنین پشتیبانی از زمان اجرا و ابزار برای تشخیص نشت حافظه وجود دارد. زمان اجرا Objective-C هر گونه نشت شناسایی شده را هنگام خروج از برنامه گزارش می دهد، که یکی از دلایلی است که J2ObjC تست های JUnit را به باینری های اجرایی ترجمه می کند. Xcode از Clang استفاده می کند و آن کامپایلر دارای تجزیه و تحلیل استاتیک عالی برای مشکلات حافظه است که Xcode با دستور Analyze آن را در دسترس قرار می دهد.
شمارش خودکار مرجع (ARC)
ARC روش مدیریت حافظه پیشنهادی اپل است. مسئولیت شمارش ارجاع را به کامپایلر منتقل میکند، که روشهای مناسب نگهداری، انتشار و انتشار خودکار را در طول کامپایل اضافه میکند. ARC از مراجع ضعیف برای دستگاه های دارای iOS 5 و بالاتر پشتیبانی می کند.
ما توصیه می کنیم که پروژه ها از ARC برای کدهای ترجمه شده استفاده کنند. کد Objective-C Transpiled درست مانند کد Objective-C دست نویس است. استفاده از ARC میتواند به توسعهدهندگان کمک کند تا از خطاهای رایج مرتبط با حافظه مانند انتشار بیش از حد یا کمارجاع اجتناب کنند و مدیریت حافظه را سادهتر و کمتر مستعد خطا کند.
توجه داشته باشید که ARC به طور پیشفرض از نظر استثنایی ایمن نیست . به طور خاص، هنگامی که استثناها پرتاب می شوند، حافظه را نشت می کند. از آنجایی که استثناها در جاوا رایج تر هستند و معمولاً قابل بازیابی هستند، این می تواند مشکل ساز باشد. استفاده از -fobjc-arc-exceptions
هنگام کامپایل با arc، نشت را با مقداری هزینه عملکرد قابل قبول برطرف می کند.
ما همچنین توصیه میکنیم که پروژههای جدید از ARC برای کد Objective-C دستنویس خود استفاده کنند و فقط در صورتی که دادههای نمایهسازی مشکل عملکرد واقعی را نشان دهد، به شمارش مراجع دستی بازگردند. هر دو کد ARC و غیر ARC را می توان بدون مشکل کامپایل و به یک برنامه مرتبط کرد.
مراجع ضعیف
فیلدها را می توان با com.google.devtools.j2objc.Weak حاشیه نویسی کرد، که transpiler از آن برای تولید فیلدهایی استفاده می کند که از معناشناسی مرجع ضعیف Objective-C پیروی می کنند. هنگام استفاده از شمارش مرجع، به این معنی است که فیلد هنگام مقداردهی اولیه حفظ نمی شود، و زمانی که نمونه حاوی آزاد می شود، آزاد می شود. با ARC، فیلدهای ضعیف با حاشیه نویسی __unsafe_unretained
مشخص می شوند و ویژگی های مرتبط ضعیف اعلام می شوند.
در برخی موارد، یک نمونه کلاس داخلی با نمونه خارجی خود در یک چرخه مرجع قرار می گیرد. در اینجا، یک حاشیه نویسی com.google.devtools.j2objc.WeakOuter برای علامت گذاری کلاس داخلی استفاده می شود، بنابراین ارجاع به کلاس خارجی همانطور که در بالا توضیح داده شد رفتار می شود. سایر فیلدهای کلاس داخلی تحت تأثیر این حاشیه نویسی قرار نمی گیرند.
J2ObjC همچنین از کلاس WeakReference
پشتیبانی میکند، بنابراین کد جاوا که از آن استفاده میکند، هنگام ترجمه به همان روش کار میکند. توجه داشته باشید که WeakReference
ذاتاً در JVM غیر قطعی است. برنامه هایی که می خواهند با حفظ قابلیت پیش بینی از نشت حافظه جلوگیری کنند، باید @Weak
و @WeakOuter
را ترجیح دهند.
ابزارهای مدیریت حافظه
- ابزار Cycle Finder - فایل های منبع جاوا را برای چرخه های مرجع شی قوی تجزیه و تحلیل می کند.
- Xcode Instruments - مجموعه ابزارهای پروفایل Xcode.
- Xcode Memory Diagnostics - گزینه هایی را برای اجرا با تشخیص حافظه و ثبت گزارش ایجاد کنید.