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

Garbage collection in webkit documentation #71

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
138 changes: 138 additions & 0 deletions docs/Deep Dive/DOM.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,141 @@ Because JavaScript can [open a new window](https://developer.mozilla.org/en-US/d
under user gestures and have [access back to its opener](https://developer.mozilla.org/en-US/docs/Web/API/Window/opener),
multiple web pages across multiple tabs might be able to communicate with one another via JavaScript API
such as [postMessage](https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage).


# Inserting and Removing DOM Nodes

Document Object Model (DOM) manipulation is a crucial aspect of web development, allowing you to dynamically modify the structure and content of your web page. This documentation will guide you through the process of inserting and removing DOM nodes using JavaScript.



## Inserting DOM Nodes

### Creating New Nodes

To insert a new DOM element, first create the element using `document.createElement` method. This method will create a new HTML element with
a specific tag name. Once the element is created, you can further modify its attributes and content.

<h4>Example: </h4>

```
const newElement = document.createElement('div');

```
### Specifying Node Properties

Once the new node is created,you can set properties and attributes
```
newParagraph.textContent = 'This is a new paragraph.';
newParagraph.setAttribute('class', 'highlight');

```
### Locating the Parent Node
Next, you'll need to locate the parent node where the new node will be inserted:

```
const parent = document.getElementById('parent');
```

### Inserting New Node

The `appendChild` method is used to add a child node to parent node. It appends the specified child node as the last child
of the parent node.

<h4>Example: </h4>

```
parentElement.appendChild(newElement);

```

### insertBefore

The `insertBefore` method allows you to insert a new node before an existing child node within a parent node.

<h4>Example: </h4>

```
const siblingElement = document.getElementById('sibling');
parentElement.insertBefore(newElement, siblingElement);

```

### Updating Layout and Rendering

After insertion, the Webkit engine recalculates the layout and rendes the updated page.This involves reflowing the affected parts of the page to accommondate the new node.

## Removal of Nodes

### Locating the Node to Remove

To remove an existing node from the DOM, locate the node using methods like `document.querySelector()`:

```
const nodeToRemove = document.querySelector('.remove-me');
```

### Removing the Node

Remove the node using `.removeChild()` on its parent node:

```
const parent = nodeToRemove.parentNode;
parent.removeChild(nodeToRemove);
```

### Updating Layout and Rendering

Similar to insertion, removing a node triggers layout recalculations and updates in the rendering engine.

### Performance Considerations

Efficient DOM manipulation is crucial for optimal user experience.Consider the following steps:

### Batch Operations

Group multiple insertions/removals together to minimize layout recalculations:

```
const fragment = document.createDocumentFragment();
//this will append nodes to the fragment
parent.appendChild(fragment); //Single layout recalculation
```

### Using DocumentFragment

`DocumentFragment` helps with batch operations by allowing you to create node off-DOM before insertion:

```
const fragment = document.createDocumentFragment();
// Append nodes to the fragment
parent.appendChild(fragment); // Single layout recalculation
```

### CSS Classes and Styling

Apply CSS classes for styling changes instead of modifying properties individually:

```
newParagraph.classList.add('highlight');
```

### Debouncing and Throttling

For performance sensitive DOM updates triggered by events, use techniques like debouncing or throttling to control frequency:

```
function debounce(callback, delay) {
let timeoutId;
return function () {
clearTimeout(timeoutId);
timeoutId = setTimeout(callback, delay);
};
}
```

### References
* [WebKit Official Documentation](https://webkit.org/t)
* [MDN Web Docs - DOM Manipulation](https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model)


38 changes: 38 additions & 0 deletions docs/Deep Dive/JSC/GarbageCollection.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Garbage Collection

The JavaScriptCore Garbage Collector (JSC GC) in WebKit utilizes the [Riptide algorithm](https://webkit.org/blog/7122/introducing-riptide-webkits-retreating-wavefront-concurrent-garbage-collector/), an advanced and efficient memory management technique. Riptide is designed to manage memory for JavaScript objects in a way that minimizes interruptions to the running JavaScript code, improving the performance of web applications. This algorithm employs a combination of generational and concurrent garbage collection strategies, where objects are classified into different generations based on their age and usage patterns. Riptide optimizes the collection process by prioritizing younger objects for faster cleanup and concurrently collecting older objects, thereby reducing the time spent on garbage collection, enhancing the overall responsiveness and reliability of web applications. The Riptide algorithm is a critical component of WebKit's memory management system, ensuring that JavaScript code runs smoothly while efficiently managing memory resources.

## JavaScriptCore GC and C++ DOM Nodes

The JSC GC does not do any reference counting. However, on the WebCore side, DOM nodes are ref counted.To manage the lifetimes of C++ DOM nodes, a reference counting mechanism is employed.When a C++ DOM node is created, its reference count is set to 1.When an external object or JavaScript code references a DOM node, its reference count is increased.When a reference is no longer needed, the reference count is decreased. When the reference count drops to 0, the DOM node is destroyed, freeing its associated memory.

The interplay between C++ DOM nodes and GC cells (used for JavaScript objects) arises from the potential for JavaScript objects to hold references to C++ DOM nodes. This interplay can create complex scenarios, such as:

### 1. JavaScript Objects Referencing DOM Nodes:

When a JavaScript object holds a reference to a DOM node, it effectively prevents the DOM node from being destroyed as long as the JavaScript object is in scope. This can lead to memory leaks if not managed correctly.



// JavaScript object referencing a DOM node
let button = document.getElementById('myButton');
let jsObject = { element: button };




### 2. DOM Nodes Releasing JavaScript Objects:

The opposite situation is also possible. When a C++ DOM node is released by reference counting, it may result in JavaScript objects holding references to "dead" DOM nodes. Accessing these DOM nodes from JavaScript can lead to undefined behavior.


## JSC Debugging tools for the Garbage Collector

### 1. The GC Verifier:

enabled using the JSC_verifyGC and JSC_verboseVerifyGC options. This tool runs a normal GC cycle, and then stops the world and run an simple stupid full GC cycle for verification. And then the verifier compares the results of the 2 runs. Any live cells found by the GC Verifier must also be found live by the normal GC. OTOH, cells found live by the normal GC may be conservative, and is not actually live as seen by the GC Verifier. This tool is a turn key solution that documents found issues for the user to diagnose.


### 2. The Heap Verifier:

enabled using the JSC_verifyHeap option. It implements hooks into the beginning and end of GC cycles, and performs custom analysis on the live cells found. The user can enhance and tweak the Heap Verifier to detect various forms of corruption or patterns in cells in the cell graph. The user can also use the Heap Verifier to detect which GC cycle a cell was born and died in for debugging liveness issues. This tool is NOT a turn key solution. It requires the user to know what they are looking for and building on the Heap Verifier as infrastructure / framework for debugging an issue.