Now that all of our code is running fast and awesome, let's
talk a bit more about memory and how it affects the performance in our system.
Many programming languages that are known for being close to the hardware,
or rather, high performance, like C, C++,
and Fortran, usually programmers to manage memory themselves.
Effectively programmers are responsible for
allocating a block of memory and then sometime in the future de-allocating
it when they're actually done using it.
Since you define when and how much memory to allocate in free, the entire
quality of managing memory depends on your skills and effectiveness.
That's a lot of responsibility.
And the reality programmers aren't always the best at keeping track of
all those bits and pieces of memory.
I mean think about it, product development is a muddy and
crazy process and often memory ends up not getting freed properly.
These un-liberated blocks of memory, are called memory leaks and they just sit
around hogging resources, that you could use better or somewhere else.
To reduce this chaos, stress, and sometimes big money losses,
caused by memory leaks, managed memory languages were created.
The run times of these languages track memory allocations and
release memory back to the system when it's no longer being needed by
the application itself, all without any intervention from the programmer.
This art, or rather science, of reclaiming memory in a managed memory
environment is known as garbage collection, this concept was created by
John McCarthy in 1959 to solve problems in the lisp programming language.
The basic principles of garbage collection are as follows, number one,
find data objects in a program that cannot be accessed in the future for
example, any memory that is no longer referenced by the code.
And number two, reclaim the resources used by those objects.
Simple concept in theory, but it gets pretty complex once you've
got 2 million lines of code and four gigs worth of allocations.
Now think about it, garbage collection can be really gnarly, I mean,
if you've got some 20,000 allocations in your program right now.
Which ones aren't being needed anymore?
Or better yet, when should you execute a garbage collection event
to free up memory that isn't used?
These are actually very difficult questions, and
thankfully we've had about 50 years worth of innovation to improve them,
which is why the garbage collector in Android's Runtime,
is quite a bit more sophisticated than McCarthy's original proposal.
It's been built to be as fast and non-intrusive as possible.
Effectively the memory heaps in androids runtimes are segmented into spaces,
based on the type of allocation and
how best the system can organize allocations for future GC events.
As a new object is allocated,
these characteristics are taken into account to best fit what spaces should
be placed into depending what version of the android runtime you're using.
And here's the important part.
Each space has a set size,
as objects are allocated, we keep track of the combined sizes, and,
as a space starts to grow, the system will need to execute a garbage
collection event in an attempt to free up memory for future allocations.
Now it's worth putting out that GC events will behave differently
depending on what Android runtime you're using.
For example, in Dalvik many GC events are stop the world events, meaning
that any managed code that is running will stop until the operation completes.
Which can get very problematic, when these GCs take longer than normal or
there's a ton of them happening at once,
since it's going to significantly eat into your frame time.
>> And to be clear,
the Android engineers have spent a lot of time making sure that these events
are as fast as possible to reduce interruptions, that being said,
they can still cause some application performance problems in your code.
Firstly, understand that the more time your app is spending doing GCs in
a given frame, the less time it's got for the rest of the logic needed to keep
you under the 16 millisecond rendering barrier.
So if you got a lot of GCs or some long ones that are occurring right after
each other, it might put your frame processing time over the 16 millisecond
rendering barrier, which will cause visible hitching or jank for your users.
Secondly, understand that your code flow may be doing the kinds of work that
force GCs to occur more often, or making them last longer than normal duration.
For example, if you're allocating a hoard of objects in the inner most part
of a loop that runs for a long time, then you're going to be polluting your
memory heap with a lot of objects and you'll end up kicking off a lot of GCs
quickly, due to this additional memory pressure.
And even though we're in a managed memory environment,
memory leaks can still happen.
Although they're not as easy to create as the other languages.
These leaks can pollute your heat with objects that won't get freed
during a GC event, effectively reducing the amount of usable space you have and
forcing more GC events to be kicked off, in a regular fashion as a result.
So that's the deal, I mean,
if you want to reduce the amount of GC events that happen in a given frame,
then you need to focus on optimizing your apps memory usage.
From a code perspective, it might be difficult to track down where problems
like these are coming from, but
thankfully, the Android SDK has a set of powerful tools at your disposal.
Let's take a look.
الآن وبما أنه تم تشغيل كل الكود بصورة سريعة ورائعة،
دعونا نتحدث قليلا عن الذاكرة وكيف تؤثر على الأداء في نظامنا.
العديد من لغات البرمجة المعروفة بكونها على مقربة من الأجهزة،
أو بالأحرى، عالية الأداء، مثل C، C++، وفورتران،
عادة يستخدمها ما المبرمجين لإدارة الذاكرة بأنفسهم.
يعتبر المبرمجون على نحو فعال هم المسئولون عن تخصيص
مجموعة من الذاكرة، وفي وقت ما في المستقبل انهاء التخصيص
عند الانتهاء من استخدامها بالفعل.
بما إنك تعرف متى ومقدار الذاكرة المخصصة في المساحة الفارغة،
تتوقف الجودة الكاملة لإدارة الذاكرة على مهاراتك وفعاليتها.
هذا يعتبر قدر كبير من المسئولية.
في الواقع لا يعتبر المبرمجين دائما الأفضل في تتبع
كل تلك الاجزاء والقطع من الذاكرة.
لنفكر في ذلك، تعتبر عملية تطوير المنتجات عملية
معقدة وسريعة وغالبا لا تحصل الذاكرة على مساحة فارغة بشكل صحيح
تسمي هذه المجموعات من الذاكرة المحررة بتسريب الذاكرة، وهي توجد
حول الموارد المصممة، والتي يمكنك استخدامها بشكل أفضل أو في مكان آخر.
للحد من هذه الفوضى، والضغط، والخسائر الكبيرة في المال أحيانا
الناتجة عن تسرب الذاكرة، يتم إنشاء لغات الذاكرة المدارة.
يعود وقت تشغيل هذه اللغات لمخصصات تتبع الذاكرة
وتحرر الذاكرة مرة أخرى للنظام عندما لا يكون هناك حاجة اليها
بواسطة التطبيق نفسه، وكل ذلك دون أي تدخل من المبرمج.
هذا الفن، أو بالأحرى العلم، من استعادة الذاكرة في بيئة الذاكرة
المدارة يعرف بجمع البيانات عديمة النفع، تم استحداث هذا المفهوم
من قبل جون مكارثي في عام ١٩٥٩ لحل المشاكل في لغة معالجة البرمجة.
المبادئ الأساسية لجمع البيانات عديمة النفع هي كما يلي، الأول،
ايجاد كائنات البيانات في البرنامج والتي لا يمكن الوصول إليها في المستقبل
على سبيل المثال، أي ذاكرة لم يعد يتم الرجوع إليها بواسطة الكود.
الثاني، استعادة الموارد المستخدمة من قبل هذه الكائنات.
مفهوم بسيط من الناحية النظرية، ولكنه يصبح معقدا جدا بمجرد حصولك
على مليوني خط من الكود وأربع جيجابايت بمقدار المخصصات.
فكر بذلك، يمكن لجمع البيانات عديمة النفع أن تكون معقدة حقا،
إذا حصلت على ٢٠٠٠٠ من المخصصات في البرنامج في الوقت الحالي.
أي من تلك لم يعد هناك حاجة اليها بعد الآن؟
أو الأفضل، متي ينبغي عليك تنفيذ حدث جمع البيانات عديمة النفع
لإفراغ الذاكرة التي لم يتم استخدامها؟
تعتبر هذه في الواقع أسئلة صعبة جدا،
ولكن لقد كان لدينا ٥٠ سنة مهمة من الابتكار لتحسينهم،
هذا هو السبب ان جامع البيانات عديمة النفع وقت تشغيل الاندرويد،
هو أكثر تطورا من اقتراح مكارثي الأصلي.
لقد تم انشاؤها لتكون سريعة وغير تداخلية بقدر الإمكان.
يتم تقسيم الذاكرة التكويمية وقت تشغيل الاندوريد إلى مساحات،
استنادا إلى نوع التخصيص
وما هي أفضل طريقة يمكن للنظام تنظيم مخصصات أحداث GC المستقبلية.
عندما يتم تخصيص كائن جديد،
تؤخذ هذه الخصائص في الاعتبار لتناسب بشكل أفضل المساحات التي
توضع فيها اعتمادا على وقت تشغيل اصدار الاندرويد الذي تستخدمه.
وهذا هو الجزء المهم.
كل مساحة لديها حجم محدد،
عندما يتم تخصيص الكائنات، حيث نستمر في تتبع الأحجام المجتمعة
عند بدء المساحة في النمو، سوف يحتاج النظام إلى تنفيذ حدث جمع
البيانات عديمة النفع في محاولة لتحرير مخصصات الذاكرة المستقبلية
انه يستحق إطلاق أحداث GC والتي ستبدو بشكل مختلف
اعتمادا على وقت تشغيل الأندرويد الذي تستخدمه.
مثلا، في Dalvik توقف العديد من أحداث GC الأحداث العالمية، يعني
أن أي كود مدار وقت التشغيل سيتوقف حتى اكتمال العملية.
والتي يمكن ان تكون معقدة، عندما تستغرق الGC وقتا أطول من المعتاد
أو هناك مجموعة منها تحدث دفعة واحدة،
عندما تلتهم الى حد كبير الإطار الزمني الخاص بك.
ولكي تكون واضحا،
قضى مهندسي الاندرويد الكثير من الوقت للتأكد من أن هذه الأحداث
هي أسرع بقدر الإمكان للحد من الانقطاعات، وابعد قول ذلك،
ما زالت تسبب بعض المشاكل في أداء التطبيقات في الكود الخاص بك.
أولا، افهم أن قضاء تطبيقك مزيد من الوقت في القيام بحدث ال GC
في إطار معين، يمنحها وقتا أقل بالنسبة للمنطق اللازم للحفاظ على بقاءك
أقل من ١٦ ميلي ثانية في تصيير الحاجز.
حتى إذا حصلت على كثير من الGC أو بعض من تلك التي تحدث مباشرة
بعد بعضها البعض، فقد تضع وقت معالجة إطارك على أكثر من ١٦ ميلي ثانية
لتصيير الحاجز، والذي يؤدي لربط مرئي أو التخلص منها للمستخدمين.
ثانيا، افهم أن تدفق الكود يمكنه القيام بأنواع العمل التي تجبر
الGC على الحدوث أكثر، أو استمرارها لفترة أطول من المعتاد.
مثلا، إذا كنت تخصص مجموعة من الكائنات في الجزء الأكبر الداخلي
لحلقة يتم تشغيلها لفترة طويلة، ستكون على وشك تلويث
تكدس الذاكرة بالكثير من الأشياء وسينتهي بإنهاء الكثير من الGC
بسرعة، نتيجة لضغط الذاكرة الإضافية هذه.
على الرغم من أننا في بيئة الذاكرة المدارة،
فلا يزال يمكن حدوث تسرب الذاكرة.
على الرغم من انه ليس من السهل إنشاءها مثل اللغات الأخرى.
يمكن لهذه التسربات تلويث حرارتك مع الكائنات التي لن يتم افراغها
خلال حدث GC، والحد بفعالية من مقدار المساحة المستخدمة لديك
واجبار إطلاق المزيد من أحداث GC بطريقة منتظمة نتيجة لذلك.
هذه هي القصة،
إذا كنت تريد تقليل مقدار أحداث GC التي تحدث في إطار معين،
فأنت بحاجة إلى التركيز على تحسين استخدام الذاكرة لتطبيقاتك.
من منظور الكود، قد يكون من الصعب تتبع من أين
تأتي مثل هذه المشاكل،
ولكن تملك اندرويد SDK مجموعة من الأدوات القوية تحت تصرفكم.
دعونا نلقي نظرة.
Ahora que todo nuestro código se ejecuta rápido y genial, hablemos
un poco más acerca de la memoria y cómo afecta el rendimiento en nuestro sistema.
Muchos lenguajes de programación conocidos por ser cercanos al hardware,
o más bien, de alto desempeño como C, C++
y Fortran, los programadores suelen tener que administrar la memoria ellos mismos.
Los programadores son los responsables
de asignar un bloque de memoria y, posteriormente, desasignarlo
cuando han terminado de utilizarlo,
dado que uno mismo define cuándo y cuánta memoria asignar, toda la
calidad de la administración de memoria depende de tus habilidades y efectividad.
Es mucha responsabilidad.
Y la realidad es que los programadores no siempre son los mejores en controlar
todos esos trocitos de memoria.
Piénsalo, el desarrollo de productos es laborioso y
agitado, y muchas veces la memoria acaba no siendo liberada correctamente.
Esos bloques de memoria sin liberar son llamados fugas de memoria, y andan
por ahí acaparando recursos que podrías utilizar en otra parte.
Para reducir este caos, estrés, e incluso grandes pérdidas monetarias,
causadas por fugas de memoria, se crearon los lenguajes de memoria administrada.
Los tiempos de ejecución de estos lenguajes rastrean las asignaciones y
liberan memoria al sistema cuando ya no le hace falta
a la aplicación en sí misma. Sin ninguna intervención por parte del programador.
Este arte, o más bien ciencia, de recuperar memoria en un ambiente
de memoria administrada, se conoce como "recolección de basura", el concepto
fue creado en 1959 por John McCarthy para resolver problemas en el lenguaje LISP.
Los principios básicos de recolección de basura son: número uno,
encontrar objetos de datos en un programa al que no se puede acceder en el futuro,
por ejemplo, cualquier memoria que ya no esté referida por el código.
Y número dos, recuperar los recursos utilizados por dichos objetos.
El concepto es simple en teoría, pero se vuelve bastante complejo
cuando tienes 2 millones de líneas de código y cuatro gigas de asignaciones.
Piénsalo, la recolección de basura puede ser realmente irritante,
si tienes unas 20.000 asignaciones en tu programa ahora mismo,
¿cuales ya no se necesitan?
O mejor, ¿cuándo debes ejecutar un evento de recolección de basura
para liberar memoria sin utilizar?
Éstas preguntas son realmente difíciles y
afortunadamente, hemos tenido unos 50 años de innovación para mejorarlas.
Por eso el recolector de basura en el tiempo de ejecución de Android
es bastante más sofisticado que la propuesta original de McCarthy.
Ha sido creado para ser tan rápido y no invasivo como sea posible.
En efecto, las pilas de memoria en los tiempos de ejecución de Android
están segmentadas en espacios
basado en el tipo de asignación y
en cómo el sistema puede organizar mejor las asignaciones para futuros eventos GC.
Cuando se asigna un nuevo objeto,
estas características son tomadas en cuenta para ajustarse a los espacios
más adecuados, dependiendo de la versión del tiempo de ejecución Android que uses.
Y aquí viene lo importante:
cada espacio tiene un tamaño específico.
A medida que se asignan objetos, se van se van vigilando los tamaños combinados
y cuando el tamaño empieza a crecer, el sistema tendrá que ejecutar un evento
de recolección de basura, intentando liberar memoria para futuras asignaciones.
Vale destacar que los eventos de GC se comportan de forma diferente
dependiendo de cuál tiempo de ejecución de Android se utilice.
Por ejemplo, en Dalvik, muchos eventos de GC detienen los eventos mundiales,
así, cualquier código administrado que se esté ejecutando se detiene
hasta completar la operación.
Lo que genera problemas cuando los GC tardan más de lo normal, o cuando
ocurren muchos al mismo tiempo.
dado que van a consumir parte significativa de tu tiempo.
y, seamos claros,
los ingenieros de Android han invertido mucho tiempo en asegurarse de que
estos eventos sean lo más rápidos posible para evitar interrupciones.
Dicho esto, pueden causar problemas en el desempeño de aplicaciones en tu código.
En primer lugar, entiende que, mientras más tiempo pase tu app haciendo GC
en cierto marco, menos tiempo tendrá para el resto de la lógica que necesita para
mantenerte bajo la barrera de renderización de 16 milisegundos.
Así que, si tienes muchos GC, o algunos muy largos que ocurren uno
tras otro, eso podría ubicar tu tiempo de procesamiento de cuadros por sobre
los 16 milisegundos
que es la barrera de renderización, lo que causaría ralentización o fallas
a tus usuarios.
En segundo lugar, entiende que el flujo del código puede estar haciendo cosas
que obliguen a eventos GC más frecuentes o más largos de lo normal.
Por ejemplo, si estás asignando muchos objetos en la parte interior
de un lazo que se ejecuta durante largo tiempo, contaminarás
tu pila de memoria con muchos objetos y acabarás generando muchos GC
rápidamente, debido a ésta presión adicional sobre la memoria.
Incluso considerando que estamos en un ambiente de memoria administrada,
pueden ocurrir fugas de memoria.
Aunque no es tan fácil crearlas como en otros lenguajes.
Estas fugas pueden contaminar tu pila con objetos que no se liberan
durante un evento GC, reduciendo efectivamente el espacio utilizable y
obligando a que ocurran más eventos GC con regularidad.
Así que eso es,
si quieres reducir la cantidad de GC que ocurren en un cierto plazo,
debes enfocarte en optimizar el uso de memoria de las apps.
Desde una perspectiva de código, puede ser difícil detectar de dónde
salen éstos problemas, pero
afortunadamente, el Android SDK pone un juego de poderosas herramientas
a tu disposición.
Veamos.
Maintenant que tout notre code est optimisé et que tout marche bien
parlons un peu de mémoire et de son effet sur les performances dans notre système.
Les langages de programmation qui sont connus pour être proche du matériel,
ou plutôt, de haute performance, comme C, C ++,
et Fortran, exigent pour les programmeurs de gérer la mémoire eux-mêmes.
Les programmeurs sont responsables
de l'allocation d'un bloc de mémoire, puis ensuite de sa désallocation
quand ils ont fini de l'utiliser.
Comme vous définissez quand et combien de mémoire allouer,
la qualité de la gestion de mémoire dépend de vos compétences et de votre efficacité
Une grande responsabilité.
En réalité, les programmeurs ne sont pas toujours les meilleurs
pour garder la trace de ces fragments de mémoire.
Pensez-y, le développement de produits est un processus laborieux et précis.
Et la mémoire finit souvent par ne pas être libérée proprement.
Ces blocs non libérés de mémoire, ce sont les fuites de mémoire et ils restent là
monopolisant les ressources que vous pourriez utiliser mieux ou ailleurs.
Pour réduire ce chaos, ce stress, voire de grosses pertes d'argent
dûes aux fuites de mémoire, on a créé des langages avec gestion de mémoire.
Ces langages permettent de suivre les allocations de mémoire
et libèrent la mémoire pour le système quand elle n'est plus nécessaire
pour l'application elle-même, le tout sans aucune intervention du programmeur.
Cet art, voire science, de récupération de mémoire dans un environnement
de gestion de mémoire est appelé : garbage collection, concept créé par
John McCarthy en 1959 pour résoudre les problèmes dans le langage Lisp.
Les grands principes du garbage collection sont les suivants : numéro un,
retrouver les données d'objets qui ne seront plus accessibles à l'avenir
par exemple, toute mémoire n'étant plus référencée par le code.
Numéro deux, récupérer les ressources utilisées par ces objets.
Concept simple en théorie qui devient assez complexe lorsque vous avez
2 millions de lignes de code et quatre gigas pour les allocations.
Pensez-y, le garbage collection peut être assez tordu, ainsi,
si vous avez quelque 20 000 allocations dans votre programme en ce moment,
lesquelles sont inutiles ?
Mieux : quand faut-il exécuter un événement de garbage collection
pour libérer de la mémoire qui ne sert plus ?
Ce sont des questions très difficiles en fait,
heureusement nous avons eu environ 50 ans d'innovation pour les améliorer,
c'est pourquoi le garbage collector dans Android,
est un peu plus sophistiqué que la proposition originale de McCarthy.
Il a été conçu pour être rapide et le moins intrusif possible.
Sur android la mémoire s'empile, les temps d’exécution se partagent en espaces
sur la base du type d'allocation et de la meilleure façon pour le système
de gérer les allocations pour les futurs GC.
Quand un nouvel objet est alloué,
ces caractéristiques sont considérées pour sélectionner les meilleurs espaces
selon la version d'Android runtime que vous utilisez.
Et voici la partie importante.
Chaque espace a une taille définie,
À mesure que les objets sont alloués, nous suivons le total des tailles
et quand un espace commencera à grandir, le système devra faire un événement
de garbage collection pour libérer de la mémoire pour les prochaines allocations.
Maintenant, il faut préciser que les événements GC diffèreront
selon le runtime Android que vous utilisez.
Par exemple, avec Dalvik les événements GC sont du type : « stop the world »,
ainsi tout code géré qui s'exécute s'arrête jusqu'à la fin de l'opération.
ce qui peut devenir problématique, lorsque ces GC durent plus longtemps
ou quand il y en a un peu trop à la fois,
car cela va considérablement influencer votre fréquence d'images
- Et soyons clairs,
Les ingénieurs Android ont beaucoup travaillé pour que ces événements
soient aussi courts que possible pour réduire les interruptions, cela étant dit,
ils peuvent encore causer des problèmes de performance d'appli dans votre code.
Tout d'abord, comprenez que plus votre appli. prend du temps à faire du GC
sur une frame donnée, moins elle en a pour le reste du circuit logique
qu'il faut pour rester sous la barrière des 16 millisecondes de rendu.
Donc si vous avez pleins ou de longs GC se produisant d'affilée,
cela pourrait faire passer votre de temps de traitement de frame au-dessus de
ces 16 millisecondes de rendu, causant des saccades pour vos utilisateurs.
Deuxièmement, sachez que votre flux de code peut faire le genre de choses
qui entraîne plus de GC, ou les faire durer plus longtemps que la durée normale.
Par exemple, si vous allouez beaucoup d'objets dans la partie la plus interne
d'une boucle qui dure longtemps, alors vous allez polluer
votre tas de mémoire avec trop d'objets et vous allez avoir un grand nombre de GC
rapidement, du fait de cette pression supplémentaire sur la mémoire
Même dans un environnement de mémoire contrôlée,
des fuites de mémoire peuvent se produire.
Bien qu'elles ne soient pas aussi faciles à créer qu'avec les autres langages.
Ces fuites peuvent polluer votre tas avec des objets qui ne seront pas libérés
avec un événement de GC, réduisant la quantité d'espace utilisable
et entraînant plusieurs événements de GC, de façon régulière par la suite.
C'est donc ça le truc,
Si vous voulez réduire la quantité de GC qui se produit dans une frame donnée,
alors vous devez optimiser l'utilisation de la mémoire de vos applications.
Sur le plan du code, traquer l'origine de ce genre de problèmes
peut être compliqué.
Heureusement, le SDK Android dispose d'un ensemble d'outils puissants pour vous.
Jetons-y un coup d’œil.
Sekarang semua kode kita berjalan cepat dan mengagumkan,
mari kita berbicara lebih banyak mengenai memori
dan bagaimana bisa mempengaruhi kinerja dalam sistem kita.
Banyak bahasa pemrograman yang dikenal dekat dengan perangkat keras,
atau lebih tepatnya, kinerja tinggi, seperti C, C ++, dan Fortran,
biasanya membutuhkan programmer untuk mengelola memorinya sendiri.
Secara efektif programmer bertanggung jawab atas
mengalokasikan blok memori dan kemudian suatu saat mengalokasikan kembali
saat mereka sudah selesai menggunakannya.
Karena Anda yang menentukan kapan dan berapa banyak memori
yang dialokasikan secara gratis,
seluruh kualitas pengelolaan memori
tergantung pada keterampilan dan efektivitasmu.
Itu tanggung jawab yang besar.
Dan secara realitas, programmer tidak selalu yang terbaik dalam melacak
semua potongan-potongan memori.
Maksudku pikirkanlah, pengembangan produk itu sulit dan
proses gila dan sering memori berakhir tidak dibebaskan dengan benar.
Blok memori yang tidak bisa dibebaskan ini
disebut kebocoran memori
dan mereka hanya diam memonopoli sumber daya,
yang bisa Anda gunakan lebih baik atau di tempat lain.
Untuk mengurangi kekacauan ini, stres, dan terkadang kerugian uang yang besar,
yang disebabkan oleh kebocoran memori, manajemen bahasa memori diciptakan.
Runtime bahasa-bahasa tersebut melacak alokasi memori dan
melepas memori kembali ke sistem ketika tidak lagi dibutuhkan oleh
aplikasi itu sendiri, semua tanpa intervensi dari programmer.
Seni ini, atau lebih tepatnya ilmu,
dari reklamasi memori dalam lingkungan memori yang dikelola
dikenal sebagai koleksi sampah, konsep ini diciptakan oleh
John McCarthy pada tahun 1959
untuk memecahkan masalah dalam bahasa pemrograman LISP.
Prinsip dasar koleksi sampah adalah sebagai berikut, nomor satu,
temukan objek data di sebuah program yang tidak dapat diakses di masa depan,
contohnya, setiap memori yang tidak lagi direferensikan oleh kode.
Dan nomor dua, merebut kembali sumber daya yang digunakan oleh objek tersebut.
Konsep sederhana dalam teori, tapi cukup kompleks setelah Anda memiliki
dua juta baris kode dan empat pekerjaan senilai alokasi.
Pikirkan tentang hal itu, pengumpulan sampah dapat benar-benar degil,
maksudku, jika Anda punya sekitar 20.000 alokasi dalam program Anda sekarang.
Mana yang tidak diperlukan lagi?
Atau lebih baik lagi, saat Anda harus mengeksekusi pengumpulan sampah
untuk membebaskan memori yang tidak digunakan?
Pertanyaan-pertanyaan ini sebenarnya sangat sulit dan
untungnya kami memiliki inovasi selama 50 tahun untuk memperbaikinya,
yang mengapa kolektor sampah di Android Runtime,
agak sedikit lebih canggih dari proposal awal McCarthy.
Alat ini dibuat untuk menjadi lebih cepat dan tidak menggangu sebisa mungkin.
Efektif timbunan memori di Androids Runtimes tersegmentasi ke dalam ruang,
berdasarkan jenis alokasi
dan cara terbaik sistem dapat mengatur alokasi untuk GC di masa depan.
Sebagai objek baru dialokasikan,
karakteristik ini dibawa ke akun ruang yang paling sesuai untuk ditempatkan
dan tergantung versi Android Runtime yang Anda gunakan.
Dan inilah bagian pentingnya.
Setiap ruang memiliki ukuran set,
saat objek dialokasikan, kami terus melacak ukuran gabungan,
dan saat ruang mulai tumbuh, sistem akan perlu mengeksekusi
koleksi sampah dalam rangka membebaskan memori untuk alokasi masa depan.
Sekarang sangat berharga menempatkan bahwa GC akan berperilaku berbeda
tergantung pada Android Runtime yang Anda gunakan.
Misalnya, di Dalvik banyak GC menghentikan peristiwa dunia,
itu artinya bahwa setiap kode yang berjalan
akan berhenti sampai operasi selesai.
Yang bisa sangat bermasalah,
saat GC memakan waktu lebih lama dari biasanya
atau ada banyak peristiwa terjadi sekaligus,
karena akan signifikan memakan frame time [kerangka waktu] Anda.
Dan harus jelas, para insinyur Android
telah menghabiskan banyak waktu memastikan peristiwa ini
secepat mungkin untuk mengurangi interupsi, hal itu bisa dikatakan,
mereka masih dapat menyebabkan beberapa masalah kinerja aplikasi
di dalam kodemu.
Pertama, memahami bahwa lebih banyak waktu aplikasi Anda
menghabiskan melakukan GC di frame yang diberikan
semakin sedikit waktu sisa logika yang diperlukan
untuk menjaga Anda di bawah 16 milidetik penghalang rendering.
Jadi jika Anda punya banyak GC atau proses setelahnya,
mungkin membuat kerangka waktu pemrosesan Anda melebihi 16 milidetik
penghalang rendering,
yang menyebabkan hitching [nebeng] terlihat atau jank untuk pengguna Anda.
Kedua, memahami aliran kode Anda dapat melakukan jenis pekerjaan yang
memaksa GC terjadi lebih sering,
atau membuat mereka bertahan lebih lama dari durasi normal.
Misalnya, jika Anda mengalokasikan
menimbun benda di bagian dalam loop [lingkaran]
yang berjalan untuk waktu lama,
maka itu akan mengotori tumpukan memorimu
dengan banyak objek dan Anda akan berakhir mengeluarkan banyak GC
dengan cepat, karena tekanan memori tambahan ini.
Dan meskipun kita berada dalam lingkungan memori yang dikelola,
kebocoran memori masih bisa terjadi.
Meskipun mereka tidak semudah untuk menciptakan sebagai bahasa lain.
Kebocoran ini dapat mencemari panas dengan objek yang tak bisa dibebaskan
selama GC terjadi,
efektif mengurangi jumlah ruang yang dapat Anda gunakan dan
memaksa banyak GC yang harus dimulai,
secara teratur sebagai hasilnya. Itu adalah kesepakatannya, maksudku,
Jika Anda ingin mengurangi jumlah GC
yang terjadi di dalam frame,
Maka Anda perlu fokus pada mengoptimalkan penggunaan memori aplikasi Anda.
Dari perspektif kode,
mungkin akan sulit untuk melacak dari mana masalah seperti ini berasal,
tapi untungnya, SDK Android memiliki set alat yang kuat yang Anda inginkan.
Mari kita lihat.
もうすべてのコードが素晴らしく そして早く動くようになりましたが
メモリ管理がシステムパフォーマンスに 与える影響について少し離しましょう
ハードウェアに近いと知られる 多くのプログラミング言語は
あるいは高パフォーマンスの C, C++, Portran などもそうですが
一般的にプログラマは 自分でメモリを管理できます
プログラマは効率的な メモリ割当に責任があり
いつか割当を解除される時も 考えてメモリを割り当てる
必要があります
いつ どのぐらい自由にメモリを 割り当てるかは自分で定義できるので
メモリ管理による品質は あなたのスキルと有効性にかかっています
責任が大きいですね
ですが現実のプログラマは 常にベストな
メモリのピットとピースを 使えるわけではありません
それでこう考えました 開発は泥だらけのプロセスで
多くの場合はメモリが 正しく開放されない状態で終わります
未開放されたメモリブロックは メモリリークとよばれ
他に有効活用できるリソースを 占有してしまいます
メモリリークによる混乱やストレス ありえるコストの損失を減らすため
管理できるメモリ言語が 作られました
メモリ言語は実行時間中に メモリの割当を追跡して
アプリケーションが必要としない時に システムメモリを開放させます
プログラマの介入なしで すべては行われます
この芸術 あるいは科学は メモリ管理環境でのメモリ再利用は
ガベージコレクションとして知られています この概念は 1959 年
Lisp のプログラミング言語の問題を解決するために John McCarthy によって作られました
ガーベジーコレクションの基本的なルールは 次の通りです 1 番目は
例えば 将来的にアクセスできない プログラムやコードが
参照するあるメモリ内の データオブジェクトが見つかった時
2 番目は そのオブジェクトが 使用するリソースを取り戻します
理論的には単純な概念ですが 2 万行のコードと 4GB の割当メモリを
持つ場合 かなり複雑になります
今その話をしています ガベージコレクションは凄いことができると
プログラムが 20,000 の 割当を持つ場合なら
何をすることが必要ですか？
いっそ使用されないメモリを 開放するためにガベージコレクションを
実行した方がいいと思いませんか？
これは実際には とても複雑な問題であり
ありがたいことにも私たちは 約 50 年で革新を得ており
Android ランタイムの ガベージコレクターは
マッカーシーの当初の提案よりも 洗練されたものになりました
できるだけ早く そして干渉しないようにです
Android ランタイムのメモリヒープを 効果的に分配することは
割当タイプに基づいており さらに
将来のGCイベントに割り当てることで ベストなシステム運用かできるようになります
また 新しいオブジェクトにも 割り当てられ
使用している Android ランタイムの バージョンにより
置かれるべきベストな スペースを考慮してくれます
そして ここが 需要な部分です
各スペースの大きさの設定は
割当られたオブジェクトによります そして それらの合計サイズも追跡しており
スペースサイズが大きくなると ガベージコレクションを実行して
将来の割当のためにメモリを開放することを システムは必要とします
GC イベントの価値は Android ランタイムで
使用しているものに応じて 異なる動作をすることにあります
たとえば多くの Dalvik は GC イベントが終わるまで
実行中の管理コードを 停止するようにしています
GC は通常よりも時間がかかる時や 大幅なフレームレートを占有された時
問題があるときに一度起こすと
非常に問題解決に役立ちます
>> 明確にしておきたいことは
Android エンジニアはこのイベントに できるだけ速度を早くしたり
フリーズを減らすための使用に 多くの時間を使っていますが
これはアプリケーションのコード内の パフォーマンス問題を起こす可能性があります
まずは GC は多くの時間を与えられた フレームの中で消費していることを
理解する必要があります そして残りのロジックは
1000 分の 16 以下のレンダリングバリアを 維持するために使われます
もし多くの GC や長い何かが お互い右に発生したら
たぶんフレームのプロセス時間が 1000 分の 16 秒を超えていることを意味するので
ユーザーに良いようには 見えないでしょう
次に コードの流れによっては GC がより多く動いたり
普通の状態よりも長く 作動することがあると理解してください
たとえば あるオブジェクトのかたまりの中に より長い時間をかけてループするように
割り当てるなら 多くのオブジェクトで 複雑になったメモリヒープを
早くたくさんの GC で 片づけさせることで
追加的なメモリ活用を 手伝うことおができます
ですが 私たちのメモリ管理環境からは
相変わらずメモリリークが起きています
だとしても 他の言語を作ることは 容易ではありません
メモリリークは使用可能なスペースを減らし
定期的に GC イベントを 強制終了させてしまうため
オブジェクト使用からの熱を 効果的に解除できなくなります
ここで選択しなければなりません
もし与えられたフレームレートの中で 起こる GC イベントの量を減らしたい場合は
アプリのメモリ使用量を最適化することに 集中することを選ぶ必要があります
コードの観点から 問題がどこから起きているかを 特定することはとても
難しいですが ありがたいことに
Android SDK はそれを処理するための 強力なツールセットを持っています
見てみましょう
이제 저희 코드가 빨라졌으니
메모리에 대해 조금 더 얘기해봐요
특히 메모리가 시스템 성능에 어떤 영향을 미치는지 말이에요
하드웨어에 친숙한 고성능 언어로 알려진
C, C++, Fortran 같은 프로그래밍 언어는
프로그래머가 메모리를 직접 관리하도록 해요
메모리를 할당하는 건 프로그래머의 몫이죠
메모리 사용이 끝나면 반납하는 것도 마찬가지입니다
메모리를 언제, 얼마만큼 할당할지를 직접 결정하니
메모리 관리의 효율성은 여러분의 능력에 달려있어요
책임이 막중하죠
게다가 대부분의 프로그래머들은
그 많은 메모리 조각들을 잘 관리하지도 못해요
생각해보세요 제품 개발은 지저분하고 정신없는 작업이에요
그래서 메모리 반납은 제대로 이루어지지 않죠
이런 반납되지 않은 메모리 조각을 메모리 누수라고 해요
가만히 앉아서 리소스만 잡아먹게 됩니다
더 좋은 용도로 쓰일 수 있는 리소스를 말이죠
메모리 누수로 인한 문제, 스트레스, 그리고 금전적 손해를 줄이기 위해
메모리 관리 언어가 생겼어요
메모리 관리 언어의 런타임은 할당된 메모리를 추적하고
애플리케이션이 더 이상 필요하지 않은 메모리는 다시 시스템으로 반납합니다
프로그래머가 건드리지 않아도 말이죠
메모리 관리 환경에서 메모리를 회수하는 예술, 아니 기술은
Garbage collection(GC)이라고 불러요
GC의 개념은 1959년에 존 맥카시가
LISP 프로그래밍 언어의 문제를 해결하기 위해 만들었어요
GC의 기본적 원칙은 다음과 같아요
첫째, 프로그램에서 더 이상 접근할 수 없는 데이터 객체 찾기
코드에서 더 이상 참조하지 않는 메모리 주소 같은 것 말이죠
둘째, 이런 객체가 사용하던 리소스 회수하기
이론적으론 간단하지만 순식간에 많이 복잡해집니다
2백만 줄의 코드와 4GB만큼의 메모리 주소 할당이 있다면 말이죠
생각해보세요 GC는 정말 복잡할 수 있어요
지금 당장 여러분의 프로그램에서 2만 개의 메모리 할당이 있다면
필요하지 않은 메모리들은 어떤 건가요?
아니면 필요하지 않은 메모리를 수거하기 위한 GC 이벤트는 언제 실행해야 하나요?
이것들은 실제로 매우 어려운 문제들입니다
다행히도 GC 기술이 50년에 걸쳐 개선되고 보완된 덕분에
안드로이드 런타임의 GC는 McCarthy의 기존 아이디어보다 더 세련된 기능을 수행합니다
최대한 거슬리지 않고 빠르게 수행되도록 제작되었어요
안드로이드 런타임의 메모리 힙은
스페이스라는 단위로 나누어져 있습니다
메모리 할당의 종류와
시스템이 메모리를 정리할 수 있는 가장 효율적인 방법으로 나눕니다
추후에 발생할 GC 이벤트에 대해서 말이죠
새로운 객체가 메모리에 할당되면
객체의 특징을 고려해 가장 적절한 스페이스로 배정해요
배정 방법은 안드로이드 런타임 버전에 따라 달라요
자 이제 중요한 부분을 말씀드릴게요
각 스페이스는 크기가 정해져있어요
객체가 추가적으로 메모리를 할당받으면
스페이스의 총 크기를 기록해요
스페이스가 커지면 시스템은 추후의 메모리 할당을 위해 GC를 실행해요
하지만 GC 이벤트 진행 방식은 바뀌어요
안드로이드 런타임 버전에 따라 말이죠
예를 들어 Dalvik에서의 GC 이벤트는 stop-the-world(앱 정지) 이벤트에요
즉 GC 이벤트가 완료되기 전까지 다른 작업도 멈추는 거죠
하지만 이 방법은 문제가 발생할 수 있어요
GC의 실행 시간이 길어지거나 여러 GC 이벤트가 연이어 발생하면 말이죠
기기의 프레임 타임을 많이 사용하게 되니까요
안드로이드 개발자들은 GC 이벤트를 최대한 빠르도록 설계하는데 심혈을 기울였어요
성능에 대한 영향을 최소화하기 위해 말이죠
이런 노력에도 불구하고 애플리케이션 성능에 문제를 일으킬 수 있습니다
우선 애플리케이션이 한 프레임에서 GC를 수행하는 시간이 길수록
다른 로직 계산들이 사용할 수 있는 시간이 줄어들어요
16ms의 총 렌더링 시간 중 말이죠
그렇기 때문에 하나의 긴 GC나 여러개의 연속적인 GC가 있다면
프레임 처리 속도가 16ms를 넘어갈 수 있어요
그러면 사용자는 렉이나 튀는 현상을 경험하죠
두 번째로 여러분의 코드 흐름이
보다 자주 GC를 일으킬 수 있고
혹은 너무 긴 GC를 일으킬 수도 있다는 점을 기억하세요
예를 들어 루프의 깊숙한 곳에서 객체를 대량으로 할당하면
객체들이 메모리 힙을 오염시키고
짧은 시간 내에 많은 GC들을 쳐내야 할 거예요
이 과도한 메모리 압박으로 말이죠
그리고 메모리 관리가 잘 된 환경에 있다 하더라도
메모리 누수는 일어날 수 있어요
물론 다른 언어보단 발생하기 어렵지만요
이런 메모리 누수는 힙에서 자리를 차지하고
GC 이벤트에서도 반납되지 않아
다른 자료가 사용할 수 있는 메모리가 줄어
GC가 더 자주 발생하게 됩니다
이게 현실이에요
한 프레임에서 발생하는 GC 이벤트의 개수를 줄이시려면
여러분 애플리케이션의 메모리 사용을 최적화해야 해요
코드를 보면 메모리 문제가 어디서 발생하는지 찾기 어렵지만
안드로이드 SDK는 이 문제를 해결하기 위한 강력한 툴 몇 가지를 제공하죠
한번 볼까요
Agora que o nosso código está rodando rápido e perfeito,
vamos falar mais sobre memória e como afeita a desempenho do sistema.
Muitas linguagens de programação que são conhecidas por ser próximas do hardware,
ou melhor, de alto desempenho, como C, C++,
e Fortran, fazem os programadores gerir a memória.
Programadores são responsáveis
por alocar um bloco de memória e então no futuro desalocar
quando ele acabou de usar.
Desde que você defina quando e a quantidade de memória para desalocar,
toda a qualidade de gerir a memória depende das suas habilidades e eficiência.
É muita responsabilidade!
E na realidade, programadores não são sempre os melhores em manter
o controle dos bytes e memórias.
Pense nisso, o desenvolvimento de produto é um confuso
e louco processo e geralmente a memória não é liberada adequadamente.
Esses blocos de memória não liberados, são chamados de vazamento e eles ficam
monopolizando recursos, que poderiam ser melhor aproveitados em outro lugar.
Para diminuir esse caos, estresse e às vezes perda de dinheiro,
causado pelo vazamento, a linguagem de gerenciamento de memória foi criada.
O tempo de execução dessa linguagem controla as alocações de memória e
libera a memória para o sistema quando não está mais sendo usada
pelo aplicativo, tudo sem nenhuma intervenção do programador.
Essa arte, ou melhor, ciência de recuperar memória em um ambiente de memória
gerenciada é conhecido como coletor de lixo. Esse conceito foi criado,
por John McCarthy em 1959 para solucionar problemas na programação de linguagem LISP.
Os princípios básicos da coleta de lixo, são as seguintes:
1 - Achar dados de objetos no programa que não podem ser acessados no futuro
por exemplo, qualquer memória que não é mais referenciada por um código.
E, 2 - recuperar os recursos usados por esses objetos.
Conceito simples na teoria, mas fica bem complexo uma vez que
você tem 2 milhões de linhas de códigos e quatro giga para alocar.
Pense sobre a coleta de lixo, pode ser realmente disforme,
se você tiver 20.000 alocações no seu programa agora
quais não serão mais necessárias?
Ou ainda, quando você deve rodar a coleta de lixo
para liberar a memória que não está sendo usada?
São perguntas difíceis, e
ainda bem que temos quase 50 anos de inovações que melhoraram
e é por isso que o coletor de lixo no Android Runtime,
é um pouco mais sofisticado que o modelo original.
Ele foi construído para ser mais rápido e menos invasivo possível.
Efetivamente, os heaps de memória nos androids são segmentadas em espaços,
baseado no tipo de alocação
e o quão melhor o sistema consegue alocar para futuros eventos GC.
Quando um novo objeto é alocado,
essas características são levadas em consideração para saber em qual espaço
deve ser alocado, dependendo da versão do android em uso.
Um fato importante.
Cada espaço tem um conjunto de tamanho
quando os objetos são alocados, nós analisamos os espaços combinados
e quando um espaço aumenta, o sistema precisa executar uma coleta de lixo
na tentativa de liberar a memória para alocações futuras.
Agora, vale frisar que cada coleta de lixo será diferente,
dependendo da versão do Android usada.
Por exemplo, em Dalvik, muitos eventos são relevantes, significando
que qualquer código gerenciado que esteja rodando vai parar até acabar a coleta.
O que pode ser problemático quando esses GC demoram mais que o normal
ou quando vários acontecem ao mesmo tempo
pois irão tomar uma parte do seu tempo de sistema.
E para ficar claro,
os desenvolvedores de Android trabalharam para assegurar que esses eventos
fossem os mais rápido possíveis para reduzir as interrupções, com isso
eles ainda podem causar problemas nos aplicativos do seu código.
Primeiro, entenda que quanto mais tempo seu aplicativo perde fazendo GC,
em um determinado período, menos tempo ele tem para manter os processos necessários,
abaixo de 16 milissegundos da barreira de renderização.
Então se existem vários ou longos GC, que acontecem um após o outro
pode aumentar o tempo de processo do sistema em mais de 16 milissegundos
da barreira de renderização, levará a uma inutilização ou atraso para os usuários.
Segundo, entenda que o fluxo de código pode estar fazendo o tipo de trabalho
que obriga o processo GC a ocorrer mais vezes, ou que durem mais que o normal.
Por exemplo, se você está alocando as reservas de objetos na parte oculta
do loop que roda por mais tempo, então você estará poluindo sua
memória heap com objetos e acabara acontecendo vários GC
continuamente, por conta dessa pressão da memória adicional.
E mesmo estando em um ambiente gerenciável de memória,
vazamentos de memória podem acontecer.
Porém, eles não são tão fáceis de criar como as outras linguagens.
Esses vazamentos podem poluir seu heap com objetos que não serão liberados
durante o processo de GC, reduzindo efetivamente o total de espaço livre
forçando que mais processos GC sejam iniciados, várias vezes.
Então é isso,
se você quiser reduzir o total de eventos GC que acontecem num período,
você vai precisar focar em aperfeiçoar a memória dos seus aplicativos.
Pela perspectiva do código, pode ser difícil de achar os problemas,
como esses de acontecerem,
mas ainda bem, o SDK do Android tem ferramentas eficazes a sua disposição.
Vamos dar uma olhada.
Теперь, когда наш код работает быстро и просто замечательно,
давайте поговорим о памяти и о том, как она влияет на производительность системы.
В большинстве языков программирования более низкого уровня,
или лучше сказать, более производительных, вроде C, C++
и Fortran, обычно программистам приходится управлять памятью самим.
Фактически, программисты отвечают
за выделение блока памяти и за последующее его освобождение
по завершении работы с этим блоком.
Поскольку вы определяете момент и объём выделяемой памяти по вашему усмотрению,
итоговое качество управления памятью будет зависеть от ваших навыков и эффективности.
На вас ложится большая ответственность.
И обычно программисты не всегда могут наилучшим образом следить
за всеми теми битами и байтами памяти.
Разработка продукта - это всегда тяжелый процесс,
и память часто заканчивается будучи не освобождённой верным образом.
Такие неосвобождённые блоки памяти зовутся утечками памяти, и они просто висят,
занимая ресурсы, которые вы бы могли потратить с большей пользой где-либо ещё.
Чтобы уменьшить этот беспорядок, стресс, а иногда и снизить затраты,
вызванные утечками памяти, были разработаны языки с управлением памятью.
Исполнительная среда в этих языках следит за выделением памяти и
возвращает память системе, когда она уже более не используется
самим приложением, всё это без какого-либо контроля со стороны программиста.
Это искусство, или скорее наука, перераспределения памяти в среде
с управлением памяти известно как сбор мусора. Эта концепция была создана
Джоном МакКарти в 1959 году для решения проблем в языке LISP.
Основные принципы процесса сборки мусора следующие: первое,
найти объекты данных в программе, которые будут недоступны в дальнейшем,
например, какой-либо участок памяти, на который код не ссылается.
И второе, заново использовать ресурсы, используемые другими объектами.
В теории концепция проста, но все становится очень сложным,
когда у вас 2 миллиона строк кода и 4 гигабайта памяти к распределению.
Теперь подумайте, сборка мусора может быть действительно полезна,
когда у вас имеется около 20 000 выделений памяти в программе.
Какие из них уже не нужны?
Или лучше спросить, когда следует запустить событие сборки мусора,
чтобы освободить неиспользуемую память?
Это сложные вопросы, на самом деле,
но к счастью у нас было почти 50 лет на разработки, чтобы внести улучшения,
и вот почему сборщик мусора в среде выполнения Android
представляет собой намного более мощную систему, чем оригинальная идея МакКарти.
Он создан, чтобы быть настолько быстрым и незаметным, насколько это возможно.
По сути, участки памяти в среде выполнения Android разделены на пространства
на основе типа выделения и того,
как система сможет организовать выделения памяти для событий СМ наилучшим образом.
Как только выделяется объект,
данные характеристики учитываются при выборе наиболее подходящего пространства,
в зависимости от того, какую версию среды выполнения Android вы используете.
И вот здесь один очень важный момент.
Пространства обладают заданным размером,
и когда объекты выделяются, мы следим за общим размером,
и по мере роста объема пространства системе необходимо вызвать событие
сбора мусора в попытке высвободить память для будущих выделений.
Здесь важно подчеркнуть, что события СМ будут вести себя по-разному,
в зависимости от используемой версии среды выполнения Android.
Например, в Dalvik многие события СМ останавливают основные события,
то есть любой запущенный управляемый код будет остановлен до конца операции.
Это может стать очень проблематичным, если такие события будут длиться дольше,
либо их будет слишком много,
поскольку это будет значительно снижать частоту смены кадров.
>> И чтобы внести ясность,
инженеры Android потратили много времени, пытаясь добиться того, чтобы эти события
выполнялись как можно быстрее, чтобы снизить прерывания, которые, как сказано,
могут вызвать снижение производительности вашего кода.
Во-первых, поймите, что чем больше времени ваше приложение тратит на сбор мусора в
данном цикле, тем меньше времени остается на остальные операции при необходимости
поддержания времени в пределах 16-мсек порога отрисовки.
Поэтому, если у вас запускается множество событий СМ, либо очень долгие события идут
одно за другим, это может привести к превышению 16-мсек порога отрисовки
временем обработки кадра, что вызовет скачки или запаздывания у пользователей.
Во-вторых, поймите, что, возможно, ваш код делает что-то такое, что
заставляет запускать сбор мусора чаще, либо удлинняет этот процесс.
Например, если вы выделяете множество объектов в самом внутреннем цикле,
который работает очень долго, вы, таким образом, засоряете память
множеством объектов, и вам придётся запускать множество событий сбора мусора
очень быстро из-за такой дополнительной нехватки памяти.
И несмотря на то, что мы работаем в среде управляемой памяти,
утечки памяти всё-таки происходят.
Хотя они появляются и не так просто, как в других языках.
Такие утечки могут засорять память объектами, которые не будут удаляться
во время событий сбора мусора, снижая размер используемого пространства
и приводя в итоге к вызову ещё большего числа событий СМ лавинообразно.
Поэтому здесь нужно выбирать:
если вы хотите снизить количество событий СМ за текущий цикл обработки кадра,
то вам придётся заняться оптимизацией использования памяти вашим приложением.
С точки зрения кода, отследить то, откуда возникают подобные проблемы,
может быть не просто,
но, к счастью, Android SDK содержит в себе для этого мощные средства.
Давайте рассмотрим их.
Şimdi tüm kodlarımız hızlı ve harika çalışıyor, o zaman sistemimizde
performansı etkileyecek bellek hakkında biraz daha konuşalım.
Donanıma yakın olduğu bilinen çoğu programlama dilleri veya tersine,
yüksek performans, C,C++, ve Fortran, genellikle belleğin
kendisini yöneten programlayıcılardır.
Etkin olarak programlayıcılar bellek blokajının tahsis
edilmesinden ve bazen ileride kullanmayı tamamladıklarında kaynağı
serbest bırakmaktan sorumludurlar.
Ne zaman ve ne kadar belleğin boşta tahsis edilmesini siz belirlediğiniz için, yönetme
belleğinin toplam kalitesi sizin becerilerinize ve etkinliklerinize
bağlıdır. Bu çok büyük sorumluluktur.
Ve gerçek programlayıcılar her zaman bellek bölümlerinin ve bitlerinin
tümünü takip edenler değillerdir.
Bunu düşünün demek istiyorum, ürün geliştirme kirli ve çılgınca
bir süreçtir ve çoğu zaman düzgünce serbest bırakılmadan sonuçlanır.
Bu serbest bırakılmamış bellek bloku bellek sızıntısı olarak bilinmekte ve
başka bir yerde daha iyi kullanabileceğiniz kabarıklık kaynağında bulunmaktadır,
Bellek sızıntısının neden olduğu bu kaosu, stresi ve bazen büyük para
kayıplarını azaltmak için yönetici bellek dilleri oluşturulur.
Uygulamanın kendisi tarafından gerekli olmadığı zaman, bu dillerin çalışma süresi
bellek tahsislerinin çalışma süreleri ve belleğin sisteme geri serbest bırakılması,
bunlar programlayıcıdaki müdahalelerdir. Bu tür veya bir yönetici belleği
ortamında iddia edilen tercihan bilim, çöp toplama
olarak bilinmektedir, bu konsept 1959 yılında John McCarthy tarafından
lisp programlama dilinde problemleri çözmek için oluşturulmuştur.
Çöp toplama olayının temel ilkeleri şöyle: bir numara, örneğin ileride
ulaşılamayan bir programda veri objelerini bulma ve kod tarafından artık
başvurulmayan herhangi bir bellek.
İkinci sırada, bu objeler tarafından kullanılan kaynakların geri kazanılması.
Teoride basit bir konsept ancak 2 milyon kod çizginiz olduğunda ve tahsis
değeri dört olduğunda oldukça karmaşık olmaktadır.
Şimdi bunu düşünün, çöp toplama olayı gerçekten mükemmel olabilir, burada
şu anda programınızda eğer 20,000 tahsisiniz varsa demek istiyorum.
Hangilerine artık ihtiyaç yok?
Veya daha iyisi, kullanılmayan belleği boşaltmak için ne zaman çöp toplama
olayını gerçekleştirmelisiniz?
Aslında bunlar çok zor sorular ve iyi ki bunları geliştirmek için inovasyon
değerinde 50 yıl geçirmişiz, bu nedenle Android Program Hatasında çöp
tolayıcısının neden McCarthy'nin orijinal önerisine göre
biraz daha gelişmiş sofistike olduğunu anlıyoruz.
Mümkün olduğunca hızlı ve kesintisiz yapılmıştır.
Etkili olarak, tahsis türüne ve ileriki GC olayları için sistemin ne kadar iyi
tahsisleri organize ettiğine bağlı olarak android program hatalarındaki
bellek yığınları aralıklara segmentlere ayrılırlar.
Yeni bir obje tahsis edildiğinde, kullanmış olduğunuz android programlama
hatasının sürümüne bağlı olarak hangi aralıkların yerleştirilmesi
gerektiğiyle ilgili en iyi bu karekteristikler hesaba katılıyor.
Ve işte önemli bir bölüm. Objelerin
serbest kalması gibi her aralığın bir ayar boyutu var, biz kombine
boyutları takip edeceğiz ve aralık büyüdükçe sistem gelecekteki
tahsisler için belleği boşaltmak için çöp toplama
olayını gerçekleştirmesi gerekecektir.
Şimdi kullanmış olduğunuz Android program işleyişine bağlı olarak GC
olayının farklı olarak davranmasına değer.
Örneğin, Dalvik'te çoğu GC olayı dünya olaylarını durdurur, işlem
tamamlanana kadar çalışan herhangi yönetici kodu duracaktır demektir.
Ki bu, eğer GC'ler artık normal değilse veya zaman diliminizde önemli
harcamalara neden olduğundan bir seferinde binlercesi oluyorsa
çok problemle olabilirler.
>> Ve açık olmak gerekirse, söylenen kesintileri azaltabilmek ve mümkün
olduğunca hızlı bir şekilde bu olaylardan emin olmak için Android mühendisleri çok
fazla zaman harcadılar. Kodunuzda hala bazı uygulama performans problemlerine
neden olabilirler. İlk olarak, ne kadar verilen çerçevede
uygulamanız GC yapmada zaman harcıyorsa,
o kadar az 16 milisaniye engel oluşturma çerçevesinde
tutmak için geri kalan mantığın ihtiyacı vardır.
Eğer çok fazla GC'niz varsa veya her birisinden sonra oluşan uzun bir şey varsa,
çerçeve işleme sürenizi 16 milisaniye engel oluşturma içerisine koyabilir ki bu
görülebilir bağlanmaya veya kullanıcınız için saçmalıklara neden olabilecektir.
İkinci olarak, kod akışınız GC'nin daha sık olmasına zorlayan bir tür
olabilir veya bu normal süreden daha uzun sürdürebilir.
Örneğin uzun süre çalışan döngü içerisinde büyük bir bölümdeki
obje stoklarını tahsis ederseniz, sonra çok sayıda objeyle bellek
yığıntınızı kirletirseniz, bu ilave bellek basıncından dolayı çok
sayıda GC başlatarak hızlıca tüketirsiniz.
Yönetici bellek ortamında olmamıza rağmen,
bellek sızıntısı hala olabilir.
Diğer diller kadar oluşturması kolay olmamalarına rağmen.
GC olayı esnasında boşalamayacak objelerle sıcaklığınızı bu sızıntılar
etkileyebilir, sonuç olarak düzenli bir moda dahilinde etkin birşekilde
sahip olduğunuz kullanılabilir alan miktarını azaltarak ve daha fazla GC olayı
başlatılmasını zorlayarak. İşte anlaşma, verilen çerçevede eğer GC miktarı
olayını azaltmak istiyorsanız, uygulama bellek kullanımınızı
iyileştirmeye odaklanmanız gerekmektedir, demek istiyorum.
Kod perspektifince, problemlerin nereden geldiğini izleyerek bulmak
zordur ancak iyi ki Android SDK emrinize hazır bir
şekilde güç araç setine sahip.
Haydi bir göz atalım.
Vì tất cả mã code của chúng tôi đều chạy rất nhanh và tuyệt vời,
hãy nói thêm một chút về bộ nhớ và cách nó ảnh hưởng đến hiệu suất trong hệ thống.
Nhiều ngôn ngữ lập trình được biết đến là gần với phần cứng,
hay đúng hơn là hiệu suất cao, như C, C ++, và Fortran,
thông thường bản thân các lập trình viên tự quản lý các bộ nhớ.
Thực ra lập trình viên chịu trách nhiệm phân bổ khối bộ nhớ
và đôi khi giải phóng nó
trong tương lai khi họ đã thực sự sử dụng xong.
Vì bạn xác định khi nào và bao nhiêu bộ nhớ được phân bổ trống nên toàn bộ
chất lượng quản lý bộ nhớ phụ thuộc vào kỹ năng và hiệu quả của bạn.
Đó đúng là một trách nhiệm lớn.
Trên thực tế các lập trình viên không luôn làm tốt
việc theo dõi từng mảnhbộ nhớ như vậy.
Tôi muốn nói, hãy nghĩ rằng phát triển sản phẩm
là quá trình hỗn độn và rối loạn và thường bộ nhớ không giải phóng đúng cách.
Những khối bộ nhớ chưa được giải phóng này gọi là các lỗ hổng bộ nhớ,
chúng nằm quanh các tài nguyên bị tiêu hao
nơi bạn có thể tận dụng tốt hơn hoặc ở đâu đó.
Để giảm sự hỗn loạn, căng thẳng và đôi khi là tổn thất lớn về tiền bạc
gây ra bởi lỗ hổng bộ nhớ, các ngôn ngữ bộ nhớ có quản lý đã được tạo ra.
Những thời gian chạy của các ngôn ngữ này theo dõi việc phân bổ bộ nhớ
và giải phóng bộ nhớ trở lại hệ thống khi nó không còn cần thiết
với chính ứng dụng đó, tất cả không cần bất kỳ can thiệp nào của lập trình viên.
Nghệ thuật, hay đúng hơn là khoa học dành lại bộ nhớ trong một môi trường bộ nhớ có
quản lý được gọi là garbage collection,
khái niệm được John McCarthy nghĩ ra vào năm 1959
nhằm giải quyết các vấn đề trong ngôn ngữ lập trình lisp.
Có các nguyên tắc cơ bản của garbage collection như sau, đầu tiên là
Tìm đối tượng dữ liệu chương trình không thể truy cập trong tương lai,
ví dụ bất kỳ bộ nhớ nào không còn được tham chiếu bởi bản mã.
Và thứ hai là dành lại các tài nguyên được sử dụng bởi những đối tượng này.
Khái niệm đơn giản về lý thuyết nhưng sẽ khá phức tạp khi bạn có tới
hai triệu dòng mã code và bốn gigs worth phải phân bổ.
Giờ hãy nghĩ về nó, garbage collection có thể rất nổi trội,
ý tôi là nếu bạn đã có 20.000 phân bổ trong chương trình của mình lúc này.
Cái nào không còn cần thiết nữa? Hoặc thậm chí,
khi nào bạn cần tiến hành một lệnh garbage collection
để giải phóng bộ nhớ không còn được sử dụng?
Đây thực sự là những câu hỏi rất khó,
và rất may mắn chúng tôi đã có khoảng 50 năm đổi mới để cải thiện chúng,
đó là lý do garbage collector trong Runtime của Android
thực sự đã phức tạp hơn một chút so với đề xuất ban đầu của McCarthy.
Nó được xây dựng để nhanh chóng và không thể xâm nhập hết mức có thể.
Các khối bộ nhớ trong thời gian chạy của androids được chia khoảng hiệu quả
dựa vào loại phân bổ
và cách tốt nhất hệ thống có thể tổ chức phân bổ các sự kiện GC trong tương lai.
Là một đối tượng mới được phân bổ,
những đặc điểm đó được đưa vào sao cho phù hợp nhất với không gian dành cho nó
tùy theo loại phiên bản thời gian chạy của android mà bạn đang sử dụng.
Và đây là nội dung quan trọng.
Dù mỗi khoảng có một kích thước cài đặt,
khi đối tượng được phân bổ, chúng tôi vẫn theo dõi các kích thước tổng hợp
và khi một không gian bắt đầu phát triển, hệ thống phải thi hành garbage collection
nhằm nỗ lực giải phóng bộ nhớ cho các phân bổ tương lai.
Giờ thì có thể đưa ra rằng các sự kiện GC sẽ xử lý khác nhau
tùy vào loại thời gian chạy Android bạn đang sử dụng.
Ví dụ trong Dalvik, nhiều sự kiện GC sẽ chặn các sự kiện của toàn hệ thống,
nghĩa là bất kỳ mã quản lý nào đang chạy đều sẽ dừng lại đến khi nó thi hành xong.
Điều này sẽ trở thành vấn đề nếu các GC này mất nhiều thời gian hơn bình thường
hoặc cả tấn của chúng đang chạy cùng lúc,
vì nó sẽ ăn vào khung thời gian của bạn một cách đáng kể.
Và cần biết rằng,
các kỹ sư Android đã dành rất nhiều thời gian đảm bảo các sự kiện này
chạy nhanh hết mức có thể nhằm giảm thiểu gián đoạn, điều này được cho là
vẫn có thể gây ra một số vấn đề về hiệu suất ứng dụng trong mã của bạn.
Thứ nhất, phải hiểu rằng ứng dụng của bạn càng mất nhiều thời gian với các GC
trong một khung nhất định thì nó càng mất ít thời gian cho phần logic còn lại
cần có để giữ bạn trong hàng rào 16 mili giây.
Vì vậy, nếu bạn có rất nhiều GC hoặc một vài cái rất dài diễn ra kế tiếp,
nó có thể khiến thời gian xử lý khung của bạn vượt qua 16 mili giây.
việc dựng hàng rào sẽ gây ra những ràng buộc hoặc bất lợi cho người dùng.
Thứ hai, cần hiểu dòng mã của bạn có thể đang hoạt động khiến các GC
xảy ra thường xuyên hơn, hoặc khiến chúng kéo dài lâu hơn thời gian thông thường.
Chẳng hạn nếu bạn đang phân bổ một kho đối tượng tại phần trong cùng của
một vòng mã chạy trong thời gian dài,
sau đó bạn gây ô nhiễm vùng bộ nhớ với rất nhiều đối tượng
và bạn sẽ kết thúc bằng việc khởi động rất nhiều GC
một cách nhanh chóng, do áp lực bộ nhớ bổ sung này.
Và mặc dù chúng ta đang ở trong một môi trường bộ nhớ có quản lý,
các lỗ hổng bộ nhớ vẫn có thể xảy ra.
Mặc dù chúng không dễ dàng được tạo như những ngôn ngữ khác.
Những lỗ hổng này làm ô nhiễm trung tâm của bạn với các đối tượng không được
giải phóng trong một sự kiện, làm giảm đáng kể không gian mà bạn được sử dụng
khiến nhiều sự kiện GC khác khởi động theo cách thông thường do kết quả của nó.
Vì vậy, đó là thỏa thuận,
ý tôi là nếu muốn giảm số lượng sự kiện GC xảy ra trong một khung nhất định,
bạn cần tập trung vào tối ưu hóa việc sử dụng bộ nhớ cho các ứng dụng của mình.
Từ góc độ bản mã, có thể sẽ rất khó để theo dõi nơi mà các vấn đề
tương tự phát sinh,
nhưng thật may mắn, Android SDK có bộ công cụ mạnh mẽ theo ý bạn.
Hãy cùng xem nhé.
不是所有指令都执行得又快又好，
下面介绍内存及它如何影响系统运行。
普遍认为，多数程序语言接近硬件或高性能。
如C语言 C++语言和Fortran。
通常程序工程师会自己管理内存。
高手工程师对内存的分配，
会慎重理处理，
并在未来结束使用时再次分配。
一旦确认何时及怎样分配内存，
内存管理的品质就仰赖于工程师的技能跟效率。
责任重大啊！
实际情况是工程师们，
不都会去追踪那零碎的内存碎片。
程序开发是件混乱又疯狂的过程，
内存通常都没办法完全被释放。
这些被囚禁的内存块叫内存漏洞。
内存漏洞占用了大量资源，这些资源其实可以更好地使用。
为减少漏洞引起的混乱、负担、甚至资金损失，
便有了内存管理语言。
这些语言在运行时跟踪内存分配，
以便当程序不再需要时释放系统内存。
完全不用工程师亲自操作。
这项内存回收艺术或科学，在内存管理环境下叫垃圾清理。
这个设计概念是在1959年，
当初为了解决lisp语言问题，由John McCarthy发明的。
垃圾清理的基本概念有：
第一，找到未来无法存取的数据。
例如所有不受指令操控的内存。
第二，回收被利用过资源。
原理简单。但是2百万行编码，
跟4gigs的分配，在实际操作时却非常困难。
如果现在，在程序中有20000个分配。
垃圾清理定会让人困惑。
哪一个是没用的？
或者，
何时启动垃圾清理释放内存？
这些问题其实很复杂。
好在50年来，我们找到了解决问题的方法。
就是Android Runtime中的垃圾清理。
比McCarthy最初的方法更高级，
速度快且是非侵入性的。
经由分配类型，
及系统如何有效地组织分配以利GC的运行，
并作为新的配置。
所有影响android runtime的内存堆都被分割到空间中，
根据这些特点，哪些数据适合放到什么空间，
取决于哪个Android版本。
最重要的一点是，
每个空间都有预设的大小，
在分配目标时要跟踪综合大小，
且空间不断地扩大，系统需要执行垃圾清理。
以确保内存分配的正常运行。
值得一提的是使用不同的Android runtime，
GC的运行方式就会不同。
例如在Dalvik中很多GC是停止世界事件，
意思是很多指令的运行直到操作完成才会停止。
当这些GCs所用时间超过一般值，
或者一大堆一起执行会耗费庞大的幀象时间，
这是很麻烦的事情。
坦白讲，
Android工程师花费大量时间降低干扰，
确保这些程序以最快的速度运行。
话虽如此，在指令中影响程序执行的问题仍然存在。
首先程序在任意帧内执行GCs所用的时间越多，
消除少于16毫秒的呈像障碍，
所必需的时间就会变少。
如果有许多GCs或一大串指令一个接一个地操作，
帧象时间很可能会超过16毫秒的呈像障碍。
这会导致隐形的碰撞或闪躲。
其次，指令流程可能造成GCs强制执行的次数增多。
或者，执行时间超过正常值。
例如，在一个长期运行的循环最内侧分配囤积对象，
很多数据就会污染内存堆。
马上就会有许多GCs启动。
由于这一额外的内存压力，
虽然内存环境管理良好，
就算比其他语言复杂，
内存漏洞仍会产生。
这些漏洞在GCs启动时，通过无法被释放的数据污染内存堆，
严重降低可用空间的总量，
并以常规方式强制GC的执行。
就是这样，
如果要减少任意帧内启动GC的次数，
需要着重优化程式的内存使用量。
从指令的角度看，或许很难追踪这些问题的起因，
但是，
多亏Android SDK拥有一组不错的工具，
任你选择。
并非所有指令都执行得既快又棒
下面介紹內存及牠如何影響系統運行
普遍認為多數程式語言接近硬體或高性能
如C語言 C++語言
和Fortran 通常程式設計師自己管理內存
高手設計師對內存的分配
會慎重處理
并在未來結束使用時再次分配
一旦確認何時及如何分配可用內存
內存管理的品質就仰賴於設計師的技能跟效率
責任重大啊
實際情形是設計師們并不都會
追蹤那些零碎的內存碎片
程式開發是件混亂又瘋狂的過程
內存通常都沒辦法完全被釋放
這些被囚禁的內存塊叫內存漏洞
侵佔了大量資源 這些資源其實可以被更好地利用
為減少內存漏洞引起的混亂 負擔 甚至資金損失
便設計了內存管理語言
這些語言在運行時跟蹤內存分配及
當程式不再需要時釋放系統內存
完全不需要設計師的介入
這項內存回收的藝術或科學在內存管理環境下叫作碎片帳集
這個設計理念是在1959年
由John McCarthy發明的 當初是為了解決lisp語言的問題
碎片帳集的基本理念有：
第一找到未來無法存取的數據
如所有不受指令操控的內存
第二,回收被利用過的資源
原理簡單 但是2百萬行編碼
跟4gigs的分配在實際操作時卻異常復雜
如果目前在程式中有20000個分配
碎片帳集定會令人很困惑
哪一個是沒用的？
或者
何時啟動碎片帳集釋放內存？
這些問題其實很復雜
好在50年來我們找到了解決問題的方法
就是Android Runtime中的碎片帳集
比MacCarthy最初的方法更高級
速度快且是非侵入性的
經由分配類型
及系統如何有效地組織分配以利GC的運行
并作為新的配置
所有影響androids runtimes的內存堆都被分割到空間中
根據這些特點 那些數據最適合放到什么空間
取決於使用那個Android版本
最重要的一點是
每個空間都有預設的大小
目標在被分配時, 要跟蹤綜合大小
且空間不斷擴大 系統需要執行碎片帳集
以確保內存分配的正常運行
值得一提的是使用不同的Android runtime
GC的運行方式就會不同
例如在Dalvik中很多GC是停止世界事件
意思是很多指令的運行直到操作完成才會停止
當這些GCs所用時間超過一般值
或者一大堆一起執行會耗費龐大的幀象時間
這是很麻煩的事情
坦白講
Android設計師花費了大量時間降低干擾
確保這些程式以最快的速度運行
話雖如 在指令中影響程式執行的問題仍然存在
首先程式在任意幀內執行GCs所需的時間越多
消除少於16毫秒的呈現障礙
所需的合理時間就會變少
如果有許多GCs或是一大串指令一個接一個地操作
幀象時間很有可能會超過16毫秒的呈現障礙
這會導致隱形的碰撞或閃躲
其次,指令流程可能造成GCs強制執行的次數增多
或者執行時間超過正常值
例如在一個長期運行的循環最內側分配囤積對象
很多數據就會污染內存堆
馬上就會有許多GCs啟動
由於這一額外的內存壓力
盡管內存環境管理良好
就算是比其他語言復雜
內存漏洞仍會發生
這些漏洞在GCs啟動時透過無法被釋放的數據污染內存堆
嚴重降低可用空間的總量
并以常規的方式強制GC的執行
就是這樣
如果要減少任意幀內啟動GC的次數
需要著重優化程式的內存使用量
從指令的角度看或許很難追蹤這些問題的起因
但是
幸好Android SDK擁有一組有效的工具
任君支配