Lecture
Это окончание невероятной информации про сборка мусора.
...
allocation
Garbage collection
A direct comparison of the two cases is difficult, since their behavior depends on the situation. For example, in the best case for a garbage collection system, allocation simply increments a pointer, but in the best case for manual heap allocation, the allocator maintains free lists of particular sizes, and allocation requires only following a pointer. However, such size segregation usually causes a greater degree of external fragmentation, which can adversely affect cache behavior. Memory allocation in a garbage-collected language may be implemented using heap allocation behind the scenes (instead of simply incrementing a pointer), so the performance advantages listed above do not necessarily apply in that case. In some situations, especially embedded systems, it is possible to avoid the overhead of both garbage collection and heap management by preallocating memory pools and using a custom lightweight allocation/deallocation scheme.
The overhead associated with write barriers is more likely to be noticeable in an imperative-style program that frequently writes pointers into existing data structures than in a functional-style program that constructs data only once and never modifies it.
Some advances in garbage collection can be seen as reactions to performance problems. Early collectors were stop-the-world collectors, but the performance of this approach was distracting for interactive applications. Incremental collection avoided this disruption, but at the cost of reduced efficiency because of the need for barriers. Generational collection techniques are used with both stop-the-world and incremental collectors to increase performance; the trade-off is that some garbage is not detected as such for longer than usual.
Although garbage collection is usually non-deterministic, it can be used in hard real-time systems. A real-time garbage collector must guarantee that even in the worst case it will allocate a certain amount of computing resources to the mutator threads. The constraints imposed on a real-time garbage collector are usually based on either work or time. A time-based constraint would look like this: in every time window of duration T, the mutator threads must be allowed to run for at least time Tm. For work-based analysis, MMU (minimum mutator utilization) is usually used as the real-time constraint for a garbage collection algorithm.
One of the first implementations of hard real-time garbage collection for the JVM was based on the Metronome algorithm, whose commercial implementation is available as part of IBM WebSphere Real Time. [10] Another hard real-time garbage collection algorithm, Staccato, is available in IBM's J9 JVM, which also provides scalability for large multiprocessor architectures, bringing various advantages over Metronome and other algorithms that, conversely, require specialized hardware. [11]
Garbage collection as an integral attribute of the program runtime environment is used in languages based on the declarative paradigm, such as LISP, ML, Prolog, and Haskell. Its necessity in this case stems from the very nature of these languages, which contain no means of manually managing object lifetimes and have no possibility of naturally integrating such means. The main complex data structure in such languages is usually the dynamic singly linked list, consisting of dynamically allocated list cells. Lists are constantly created, copied, duplicated, composed, and split, which makes manual management of the lifetime of each allocated list cell practically unrealistic.
In imperative languages, garbage collection is one option, alongside manual management and some alternative techniques[⇨] of memory management. Here it is regarded as a means of simplifying programming and preventing errors[⇨]. One of the first compiled imperative languages with garbage collection was Oberon, which demonstrated the applicability and fairly high efficiency of this mechanism for this type of language, but it was the Java language that brought this approach wide recognition and popularity. Subsequently, Java's approach was repeated in the .NET environment and in virtually all the languages that run in it, starting with C# and Visual Basic .NET. At the same time, many interpreted languages appeared (JavaScript, Python, Ruby, Lua), into which garbage collection was included for the sake of making the language accessible to non-programmers and simplifying coding. The increase in hardware power, occurring simultaneously with improvements in the collectors themselves, meant that the additional overhead of garbage collection ceased to be significant. Most modern garbage-collected imperative languages have no facilities at all for explicit manual deletion of objects (for example, a delete operator). In systems that use an interpreter or compilation to bytecode, the garbage collector is part of the runtime environment, while in languages that are compiled to processor object code, it is implemented as a mandatory system library.
There are also a small number of languages (nim, Modula-3, D) that support both manual and automatic memory management, for which the application uses two separate heaps.


Languages such as C can usually hook into a program's memory management and allocate and free memory in the context of the program. ECMAScript, on the other hand, has no interface for accessing memory management (yes, this means there is no corresponding API). This essentially means that all rights to manage memory in the program are handed over to V8.
Since we do not have access to an infinite amount of memory, the job of the garbage collector is to go through all the objects for which memory has been allocated and determine whether they are dead or not. Those that are alive must remain in memory; those that are dead are removed, and the memory is returned to the heap.
A PHP variable is stored in a container called a "zval". Besides the type and value of the variable, the zval container also contains two additional elements. The first is called "is_ref" and is a boolean value indicating whether the variable is part of a "reference set" or not. Thanks to this element, PHP knows how to distinguish normal variables from references. Since PHP has user-level references, which can be created with the & operator, the zval container also contains an internal reference counting mechanism to optimize memory usage. This second piece of additional information, called "refcount", contains the number of variable names (also called symbols) that point to the given zval container. All variable names are stored in a symbol table, separate for each variable scope. Such a scope exists for the main script, as well as for each function and method.
A zval container is created when a new variable is created and assigned a constant
Although no variable name in any scope refers to this structure any longer, it cannot be cleaned up, because the array element "1" still refers to this array. Since there is now no way for the user to delete this data, we have a memory leak. Fortunately, PHP will delete this data when the request ends, but until then the data will occupy valuable space in memory. This situation often arises when implementing parsing algorithms or others in which child elements refer to their parents. It happens even more often with objects, because they are always implicitly used by reference.
This is not a problem if it happens once or twice, but if there are thousands or even millions of such memory leaks, they become a problem. This is especially so in long-running scripts, such as daemons, where the request never ends, or in large sets of unit tests. The latter case caused problems when running unit tests for the Template component of the eZ Components library. In some cases it can require over 2 GB of memory, which a test server does not always have.
Usually, in-memory reference counting mechanisms, such as the one PHP used previously, do not solve the problem of memory leaks caused by circular references. Starting with version 5.3.0, PHP implements a synchronous mechanism (Cycle Collection) from the study "Concurrent Cycle Collection in Reference Counted Systems", which addresses this issue.

In PHP it is possible to disable this mechanism. The reason for this, as well as for launching it manually, may be that some parts of your application can be time-critical. In such cases you may not want outside interference from the garbage collector.
Часть 1 Tracing Garbage Collection: Garbage Collection in Programming and Memory Leaks
Часть 2 Determinism - Tracing Garbage Collection: Garbage Collection in Programming and
Comments