Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Translate Garbage Collection Page into AR #73

Merged
merged 1 commit into from
Jun 8, 2020
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
164 changes: 93 additions & 71 deletions 1-js/04-object-basics/03-garbage-collection/article.md
Original file line number Diff line number Diff line change
@@ -1,63 +1,65 @@
# Garbage collection
# جمع القمامة (Garbage Collection)
تتم عملية ادارة الذاكرة في الJavaScript بطريقة تلقائية غير مرئية
نحن ننشئ لبقيم البسيطة, الكائنات , الدوال... و كل ذلك يستهلك من الذاكرة.

Memory management in JavaScript is performed automatically and invisibly to us. We create primitives, objects, functions... All that takes memory.
ما الذي سيحدث اذا لم نعد بحاجة لأحدهم ؟ كيف يكتشفها محرك ال JavaScript و يتخلص منها ؟

What happens when something is not needed any more? How does the JavaScript engine discover it and clean it up?

## Reachability
## قابلية الوصول

The main concept of memory management in JavaScript is *reachability*.
المفهوم الأساسي لعملية ادارة الذاكرة في ال JavaScript هو *قابلية الوصول.*

Simply put, "reachable" values are those that are accessible or usable somehow. They are guaranteed to be stored in memory.
ببساطة, القيم التي يمكن الوصول اليها هي القيم التي يمكن الولوج اليها و استخدامها بشكل ما, و تخزينها في الذاكرة شئ حتمي.

1. There's a base set of inherently reachable values, that cannot be deleted for obvious reasons.
1. هناك بعض القيم الأساسية التي يمكن الوصول اليها دائماو لا يمكن مسحها لأسباب واضحة.
علي سبيل المثال:

For instance:
- المتغيرات المحلية و المعاملات للدالة التي يتم استخدامها
- المتغيرات و معاملات الدوال في سلسلة متصلة من الاستدعاءات
- المتغيرات العامة
- (هنالك المزيد, بعضهم داخلي)

- Local variables and parameters of the current function.
- Variables and parameters for other functions on the current chain of nested calls.
- Global variables.
- (there are some other, internal ones as well)
هذه القيم تسمي ب *الجذور (roots)*.

These values are called *roots*.
2. أي قيمة اخري يمكن اعتبارها قابلة للوصول اليها اذا ما كان يمكن الوصول اليها بالفعل من جذر عن طريق مرجع(reference) او مجموعة من المراجع.

2. Any other value is considered reachable if it's reachable from a root by a reference or by a chain of references.
علي سبيل المثال, اذا كان هناك كائن مخزن في متغير محلي, و الكائن به خاصية مرجه لكائن اخر, يمكن اعتبار هذا الكائن انه يمكن الوصول اليه, و يمكن الوصول ايضا الي كل مراجع هذا الكائن, كما يتم شرحه في المثال التالي.

For instance, if there's an object in a local variable, and that object has a property referencing another object, that object is considered reachable. And those that it references are also reachable. Detailed examples to follow.

There's a background process in the JavaScript engine that is called [garbage collector](https://en.wikipedia.org/wiki/Garbage_collection_(computer_science)). It monitors all objects and removes those that have become unreachable.
تحدث عملية خلفية في محرك ال JavaScript يسمي ب جامع القمامة [garbage collector](https://en.wikipedia.org/wiki/Garbage_collection_(computer_science)) يتم خلالها مراقبة كل الكائنات و ازالة الكائنات التي لا يمكن الوصول اليها.

## A simple example
## مثـــال بـسـيـط

Here's the simplest example:
هذا هوا ابسط مثـال:

```js
// user has a reference to the object
// user له مرجع الي الكائن
let user = {
name: "John"
};
```

![](memory-user-john.svg)

Here the arrow depicts an object reference. The global variable `"user"` references the object `{name: "John"}` (we'll call it John for brevity). The `"name"` property of John stores a primitive, so it's painted inside the object.
السهم هنا يمثل مرجع لكائن, المتغير العام `"user"` يرجع الي الكائن `{name: "John"}` (الذي سنطلق عليه جون اختصارا).
خاصية `"name"` في كائن جون تخزن قيمة بسيطة لذا تم رسمها داخل الكائن.

If the value of `user` is overwritten, the reference is lost:
اذا تم استخدام اسم المتغير `user` مرة اخري , هنا يتم فقدان مرجع الكائن:

```js
user = null;
```

![](memory-user-john-lost.svg)

Now John becomes unreachable. There's no way to access it, no references to it. Garbage collector will junk the data and free the memory.
هنا لا يمكن الوصول الي كائن جون و بالتالي لا يمكن الدخول اليه لعدم وجود مرجع له, و هنا يأتي دور جامع القمامة للتخلص من بياناته و افراغ المساحة التخزينية.

## Two references
## مرجعين

Now let's imagine we copied the reference from `user` to `admin`:
تصور الأن اننا نسخنا مرجع `user` الي `admin`:

```js
// user has a reference to the object
// user له مرجع الي الكائن
let user = {
name: "John"
};
Expand All @@ -74,11 +76,12 @@ Now if we do the same:
user = null;
```

...Then the object is still reachable via `admin` global variable, so it's in memory. If we overwrite `admin` too, then it can be removed.
...في هذه الحالة ما زال بالامكان الوصول الي الكائن عن طريق المتغير العام `admin`, لذا فهو مخزن بالذاكرة. اذا تم استخدام المتغير `admin` في مكان أخر ايضا هنا يمكن ازالة الكائن .

## Interlinked objects
## الكائنات المترابطة

Now a more complex example. The family:
و الان الي مثال أكثر تعقيدا, كل العائلة:

```js
function marry(man, woman) {
Expand All @@ -98,15 +101,14 @@ let family = marry({
});
```

Function `marry` "marries" two objects by giving them references to each other and returns a new object that contains them both.
الدالة `marry` "تزوج" كائنين عن طريق اعطاء كل منهم مرجع للأخر و ترجع كائن جديد يحتوي كليهما.

The resulting memory structure:
البناء الناتج في الذاكرة:

![](family.svg)

As of now, all objects are reachable.

Now let's remove two references:
حتي الأن, كل الكائنات يمكن الوصول اليها.
و الأن فلنزيل اثنين من المراجع:

```js
delete family.father;
Expand All @@ -115,98 +117,118 @@ delete family.mother.husband;

![](family-delete-refs.svg)

It's not enough to delete only one of these two references, because all objects would still be reachable.
الغاء مرجع واحد فقط من المرجعين لا يكفي ,ستظل امكانية الوصول الي الكائنين ممكنة.

But if we delete both, then we can see that John has no incoming reference any more:
و لكن اذا تم الغاء المرجعين, هنا يمكن ان نري ان جون لم يعد له اي مرجع:

![](family-no-father.svg)

Outgoing references do not matter. Only incoming ones can make an object reachable. So, John is now unreachable and will be removed from the memory with all its data that also became unaccessible.

After garbage collection:
بعد عملية جمع القمامة:


![](family-no-father-2.svg)

## Unreachable island
## الجزيرة التي لا يمكن الوصول اليها

It is possible that the whole island of interlinked objects becomes unreachable and is removed from the memory.
هنالك امكانية ان تصبح جزيرة بأكملها من الكائنات المترابطة لا يمكن الوصول اليها و ان تمحي من الذاكرة.

الكائن هو كما بالمثال السابق, و بالتالي:

The source object is the same as above. Then:

```js
family = null;
```

The in-memory picture becomes:
الصورة من داخل الذاكرة تصبح كالتالي:


![](family-no-family.svg)

This example demonstrates how important the concept of reachability is.
هذا المثال يشرح اهمية مفهوم قابلية الوصول

It's obvious that John and Ann are still linked, both have incoming references. But that's not enough.
من الواضح ان جون و آن ما زالا متصلين ببعضهما بمراجع, لكن هذا غير كافي

The former `"family"` object has been unlinked from the root, there's no reference to it any more, so the whole island becomes unreachable and will be removed.
كائن `"family"` السابق فقد اتصاله بالجذر, لا يوجد له اي مرجع الآن, لذا فالجزيرة باكملها لا يمكن الوصول اليها و تتم ازالتها.

## Internal algorithms

## الخوارزميات الداخلية

The basic garbage collection algorithm is called "mark-and-sweep".
الخوارزمية الأساسية لجمع القمامة تسمي ب `"mark-and-sweep"`.

تحدث عملية جمع القمامة غالبا علي عدة خطوات:

The following "garbage collection" steps are regularly performed:
- جامع القمامة يأخذ الجذر و يضع عليه علامة
- ثم يزور كل المراجع المرتبطة به و يضع علي كل منهم علامة
- ثم يزور كل كل الكائنات التي عليها علامة و يضع علامة علي كل مراجعهم, كل الكائنات التي تمت زيارتها يتم تذكرها حتي لا تتم زيارة نفس الكائن مرتين.
- ... و هكذا الي ان يتم وضع علامة علي كل المراجع بداية من الجذر
- كل الكائنات عدي التي تم وضع علامة عليها يتم ازالتها

- The garbage collector takes roots and "marks" (remembers) them.
- Then it visits and "marks" all references from them.
- Then it visits marked objects and marks *their* references. All visited objects are remembered, so as not to visit the same object twice in the future.
- ...And so on until every reachable (from the roots) references are visited.
- All objects except marked ones are removed.
كمثال, فلنفترض ان بناء الكائن لدينا كالتالي:

For instance, let our object structure look like this:

![](garbage-collection-1.svg)

We can clearly see an "unreachable island" to the right side. Now let's see how "mark-and-sweep" garbage collector deals with it.
يمكننا بكل بساطة ملاحظة جزيرة لا يمكن الوصول اليها في الجانب الأيمن. و الآن نستطيع ان نري كيف يطبق جامع القمامة ال `"mark-and-sweep"`.

أول خطوة هي وضع علامة عل الجذر:

The first step marks the roots:

![](garbage-collection-2.svg)

Then their references are marked:
ثم وضع علامة علي كل المراجع المرتبطة به:

![](garbage-collection-3.svg)

...And their references, while possible:
...و مراجعم كذلك ان امكن

![](garbage-collection-4.svg)

Now the objects that could not be visited in the process are considered unreachable and will be removed:
و الآن, كل الكائنات التي لم تتم زيارتها في هذه العملية تعتبر كائنات لا يمكن الوصول اليها و ستتم ازالتها:

![](garbage-collection-5.svg)

We can also imagine the process as spilling a huge bucket of paint from the roots, that flows through all references and marks all reachable objects. The unmarked ones are then removed.

That's the concept of how garbage collection works. JavaScript engines apply many optimizations to make it run faster and not affect the execution.
يمكننا تخيل العملية كصب دلو كبير من الطلاء من الجذر و الذي سيسري خلال كل المراجع و يضع علامة علي كل الكائنات التي يمكن الوصول اليها, و الكائنات التي لا يمكن الوصول اليها يتم ازالتها.

تلك هي المبادئ التي يعمل علي اساسها جامع القمامة. محرك ال JavaScript يطبق العديد من التحسينات لجعله يعمل بشكل اسرع و الا يؤثر علي الآداء.

Some of the optimizations:
بعض هذه التحسينات:

- **مجموعة الأجيال** -- -- يتم تقسيم الكائنات الي مجموعتين "الجديدة", "القديمة", الكثير من الكائنات يتم انشائها و تؤدي وظيفتها و تموت بسرعة, فيمكن التخلص منها بسرعة. اما الكائنات التي تعيش لفترة طوية تصبح "قديمة" و لا يتم التحقق منها و ازالتها بنفس الكثافة.

- **المجموعة المتزايدة** --في حالة وجود العديد من الكائنات, و حاولنا المرور ووضع علامة علي الكائن كله مرة واحدة, سيستهلك هذا بعضا من الوقت مما قد يؤدي الي بعض التأخير في عملية التنفيذ, لذلك يحاول جامع القمامة تقسيم نفسه الي اجزاء, كل الأجزاء يتم استخدامها وحدها واحدة تلو الأخري, مما قد يتطلب المزيد من الادارة لمتابعة التغييرات و تسجيلها, و لكن تأخيرات عديدة صغيرة افضل من تأخير واحد كبير.


- **مجموعة وقت الخمول** -- يحاول جامع القمامة ان يعمل في حالة ان وحدة المعالجة المركزية (CPU) في حالة خمول حتي لا يؤثر علي عملية التنفيذ.

- **Generational collection** -- objects are split into two sets: "new ones" and "old ones". Many objects appear, do their job and die fast, they can be cleaned up aggressively. Those that survive for long enough, become "old" and are examined less often.
- **Incremental collection** -- if there are many objects, and we try to walk and mark the whole object set at once, it may take some time and introduce visible delays in the execution. So the engine tries to split the garbage collection into pieces. Then the pieces are executed one by one, separately. That requires some extra bookkeeping between them to track changes, but we have many tiny delays instead of a big one.
- **Idle-time collection** -- the garbage collector tries to run only while the CPU is idle, to reduce the possible effect on the execution.

There exist other optimizations and flavours of garbage collection algorithms. As much as I'd like to describe them here, I have to hold off, because different engines implement different tweaks and techniques. And, what's even more important, things change as engines develop, so studying deeper "in advance", without a real need is probably not worth that. Unless, of course, it is a matter of pure interest, then there will be some links for you below.

## Summary
هنالك العديد من التحسينات في خوارزميات جامع القمامة. و علي قدر ما اود ان اشرحها هنا,يجب ان نتوقف و ذلك لأن المحركات الختلفة تتبني طرق و حلول مختلفة و الأهم من ذلك ان الأشياء تتغير بتتطور المحركات, لذا ادرس أكثر "مقدما" فبدون الحاجة الحقيقية لمعرفتها فهي لا تستحق العناء الا ان كنت و بالطبع تمتلك الشغف للمعرفة فالروابط بالأسفل ستساعدك بالتأكيد.

## الملخص

اهم النقاط لتعرفها:

- جامع القمامة يعمل بشكل تلقائي, لا يمكن اجباره علي العمل او ايقافه
- الكائنات تظل في الذاكرة طالما كان بالمكان الوصول اليها
- كون الكائن له مرجع لا يعني بالضرورة ان يمكن الوصول اليه(من الجذر): قد تصبح مجموعة من الكائنات لا يمكن الوصول اليها

المحركات الحديثة تطور خوارزميات حديثة لعملية جمع القمامة

The main things to know:
كتاب `"The Garbage Collection Handbook: The Art of Automatic Memory Management"(R.Jones et al)` يجمع بعضها

- Garbage collection is performed automatically. We cannot force or prevent it.
- Objects are retained in memory while they are reachable.
- Being referenced is not the same as being reachable (from a root): a pack of interlinked objects can become unreachable as a whole.
اذا كنت علي علم بالمستويات العميقة من البرمجيات , فهنالك المزيد من المعلومات عن جـامع القمامة `V8` في هذا المقال

Modern engines implement advanced algorithms of garbage collection.

A general book "The Garbage Collection Handbook: The Art of Automatic Memory Management" (R. Jones et al) covers some of them.
[A tour of V8: Garbage Collection](http://jayconrod.com/posts/55/a-tour-of-v8-garbage-collection)

If you are familiar with low-level programming, the more detailed information about V8 garbage collector is in the article [A tour of V8: Garbage Collection](http://jayconrod.com/posts/55/a-tour-of-v8-garbage-collection).
تنشر ايضا [V8 blog](https://v8.dev/) مقالات حول تنظيم الذاكرة من آن الي أخر, بطبيعة الحال, لتعلم جامع القمامة يفضل ان تتهيأ عن طريق تعلم مكونات `V8` بشكل عام و قراءة مدونة
[Vyacheslav Egorov](http://mrale.ph) و الذي عمل كأحد مهندسي `V8`. استطيع ان أقول `V8` تحديدا لأنه الأكثر تغطية عن طريق المقالات علي الانترنت.
و بالنسبة للمحركات الأخري, العديد من الطرق متشابهة, و لكن جامع القمامة يختلف في نقاط عديدة.

[V8 blog](https://v8.dev/) also publishes articles about changes in memory management from time to time. Naturally, to learn the garbage collection, you'd better prepare by learning about V8 internals in general and read the blog of [Vyacheslav Egorov](http://mrale.ph) who worked as one of V8 engineers. I'm saying: "V8", because it is best covered with articles in the internet. For other engines, many approaches are similar, but garbage collection differs in many aspects.
المعرفة المتعمقة للمحركات ضرورية في حين الحاجة الي تحسينات ذات مستوي متطور, فأن تخطط لمعرفتها بعد ان تصبح علي معرفة جيدة باللغة لهي بالتأكيد خطوة حكيمة.

In-depth knowledge of engines is good when you need low-level optimizations. It would be wise to plan that as the next step after you're familiar with the language.