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擁有一組有效的工具
任君支配