漳平水仙茶属于什么茶| 竹蔗是什么| 纳豆是什么豆| 翌日是什么意思| 如是观是什么意思| 缘起是什么意思| 腰间盘突出吃什么| 为什么都开头孢不开阿莫西林| 吕布是什么生肖| 淋巴细胞绝对值偏高是什么原因| 唯心是什么意思| grace什么意思中文| 做nt需要准备什么| 咳嗽有绿痰是什么原因| geneva是什么牌子手表| 大运是什么意思| 尤文氏肉瘤是什么病| 甲胎蛋白增高说明什么| 骨骺是什么意思| 房颤什么意思| 刚产下的蚕卵是什么颜色| 心脏在什么位置图片| 醋泡黑豆有什么功效| 农历10月14日是什么星座| 嘴唇周围长痘痘是什么原因导致| 强肉弱食是什么意思| 血压高吃什么降压药| 5.25是什么星座| 神的国和神的义指的是什么| 骨头炖什么好吃| 木日念什么| 湿疹和热疹有什么区别| 什么去湿气| 尿里带血是什么原因| 咸湿佬是什么意思| 伪娘是什么意思| 心率低吃什么药最好| 直采是什么意思| 精神病是什么意思| 女性经常手淫有什么危害| jojo什么意思| 什么是射频| 命里有时终须有命里无时莫强求什么意思| 为什么总是做梦| 什么堂大什么| 十一月份属于什么星座| 胺试验阳性是什么意思| 血糖高喝什么豆浆好| 看守所和拘留所有什么区别| 开半挂车需要什么证| 山东简称为什么是鲁不是齐| 死心塌地什么意思| 白带什么颜色正常| 十二月七号是什么星座| 下肢水肿是什么原因| 烧心吃什么食物好得快| 身份证末尾x代表什么| 庞统和诸葛亮什么关系| 胃热吃什么食物好| 准确值是什么意思| 拔牙后吃什么食物最好| 企业bg是什么意思| 熬夜为什么会胖| 吉兰巴雷综合征是什么病| 羊肉与什么食物相克| 生意是什么意思| 补肾吃什么药| 吃什么药能延迟射精| 耳鼻喉属于什么科| 1月22日是什么星座| maggie什么意思| 生殖细胞瘤是什么病| 每天早上喝一杯蜂蜜水有什么好处| na什么意思| 巴基斯坦用什么语言| 医院可以点痣吗挂什么科| 神龛是什么意思| 10月23号是什么星座| 今日是什么生肖日| 降钙素原检测是查什么的| 老人不睡觉是什么预兆| 什么是辅酶q10| 肚子大了是什么原因造成的| 八月十二是什么星座| ap医学上是什么意思| 风声鹤唳是什么意思| 君子兰用什么土最好| 荨麻疹吃什么食物好| 海粉是什么| 8.11是什么星座| 胰是什么器官| 出球小动脉流什么血| 伤官配印是什么意思| 阴唇大什么原因| 下半年有什么节日| 薄谷开来为什么杀人| 蛇信子是什么| 无名指比中指长代表什么| cm代表什么单位| 乙肝表面抗体偏高是什么意思| 黑色素是什么| 牙齿有黑洞是什么原因| 兔爷是什么意思| 百香果什么时候开花结果| 胆固醇高应注意什么| 普拉提是什么意思| vk是什么意思| 接吻什么感觉| 白醋泡脚有什么好处| 雷人是什么意思啊| 放屁多吃什么药| 空腹吃柿子有什么危害| 京畿是什么意思| 奔富红酒属于什么档次| 阴唇为什么会变黑| 出国需要什么手续和证件| 澳门用什么币种| 喝酒精的后果是什么| 下元节是什么节日| 断更是什么意思| 决定的近义词是什么| 一根长寿眉预示什么| 山见念什么| 产前筛查是检查什么| cdc什么意思| May什么意思| jk什么意思| 狂犬疫苗为什么要打五针| 男人头发硬说明什么| 衄血是什么意思| 眼眶周围发黑什么原因| mra是什么意思| 感染hpv有什么症状| 目前是什么意思| 炎症是什么意思| 44岁月经量少是什么原因| 十三是什么意思| 被子植物是什么| 人为什么要生孩子| 为什么会甲状腺肿大| 便秘和腹泻交替出现是什么意思| 和胃是什么意思| 军长相当于地方什么官| 中线是什么| 检查贫血挂什么科| 孕激素是什么意思| 去台湾需要什么证件| 日成念什么| 缺铁性贫血吃什么补得快| 偶尔失眠是什么原因| 回光返照什么意思| 罗非鱼吃什么| 牙龈溃疡吃什么药| 什么的浪花| 胆囊结晶是什么意思| 今年7岁属什么生肖| 男生说gg是什么意思| 验孕棒什么时候测比较准| 边度什么意思| 得了阴虱用什么药能除根| kg是什么意思| 96166是什么电话| 属羊的是什么星座| 食管反流吃什么药最好| 为什么想到一个人会心痛| 双肾小结石是什么意思| 梦到自己生病了什么意思| 行运是什么意思| 止咳平喘什么药最有效| 牙周炎用什么漱口水好| 含漱是什么意思| bunny是什么意思| 脂肪肝吃什么药效果好| 利好是什么意思| 二月二十三日是什么星座| 梦见别人生孩子预示什么| 爷爷和孙子是什么关系| 高冷什么意思| 梵蒂冈为什么没人敢打| rarone是什么牌子的手表| 甲鱼炖什么好吃| 细胞核由什么组成| 羡慕的意思是什么| 四月七号是什么星座| 什么原因导致性功能减退| 下午三点到四点是什么时辰| 五更是什么生肖| cet是什么意思| 属鸡在脖子上戴什么好| 前列腺钙化灶是什么意思| 双一流大学是什么| sapphire手表什么牌子| 贲门松弛吃什么药| 鼠和什么属相最配对| 什么是生物制剂药| 火头鱼是什么鱼| 阿斯利康是什么药| 什么是钓鱼执法| 命犯桃花是什么意思| 缀化是什么意思| 总警司相当于大陆什么官| 囊实性结节是什么意思| 7d是什么意思| 小五行属性是什么| 南极有什么| 10月1日什么星座| 为什么大便会拉出血| 子宫发炎是什么原因引起的| 破伤风有什么症状| 谷氨酸钠是什么添加剂| 马粟是什么| 痛风什么感觉| 5月28日是什么星座| 子宫是什么样子图片| super star是什么意思| 老年人脚肿什么原因| 立夏是什么意思| 阴道菌群失调用什么药| 孕酮低吃什么药| 有骨气是什么意思| 腰痛去医院挂什么科| 老师家访的目的是什么| 胸痒痒是什么原因| 孕妇什么时候有奶水| 什么牌子的空调最好| 描红是什么意思| 什么叫消融手术| 神经官能症是什么病| 可字五行属什么| 1.22是什么星座| 做好自己是什么意思| 小孩尖叫是什么原因| 望洋兴叹什么意思| 血红蛋白是什么| 水杨酸有什么作用| 华语是什么语言| 揩油什么意思| 手上长小水泡是什么原因| 女性尿道出血是什么原因引起的| 脚面麻木是什么原因| 情何以堪是什么意思| 女的右眼跳代表什么| 血脂查什么项目| 名节是什么意思| 端午节为什么吃粽子| 樱桃什么季节成熟| 输血前常规检查是什么| 贴切是什么意思| 口腔溃疡吃什么水果| 战区司令员是什么级别| 心脏造影是什么检查| 燃气是什么气体| 乐不思蜀什么意思| 四川代表什么生肖| 什么花代表永恒的爱| 股骨径是指胎儿什么| 嘿是什么意思| 阿奇霉素和头孢有什么区别| 不让他看我的朋友圈是什么效果| 名创优品是卖什么的| 什么人容易得布病| 什么克木| 文曲星下凡是什么意思| 喉炎用什么药| 百度

美刊关注中国海军陆战队近期演习:万余官兵跨区机动两千公里

Web Inspector now includes two new timelines for debugging a webpage’s memory usage. The first is a high-level Memory timeline intended to help developers to better understand the memory characteristics of their webpages, to identify spikes, and to detect general memory growth. The second is a detailed JavaScript Allocations timeline that allows developers to record, compare, and analyze snapshots of the JavaScript heap; useful for finding and addressing JavaScript memory growth and leaks.

Memory Timeline

Webpages come in all shapes and sizes. There may be static pages with lots of images and presentational animations that spike in memory, which can cause a sudden termination on memory-constrained platforms. Or they may be long-living interactive JavaScript applications that start small and accumulate memory over time and slowing down after long use. The high-level Memory timeline helps categorize how memory is being used and identify what may need further investigation.

Memory Timeline

The Memory timeline shows the total memory footprint of the inspected page. It breaks the total memory out into four different categories:

  • JavaScript – JavaScript heap size. This includes JavaScript objects, strings, functions, and corresponding engine data associated with these objects. This section will only ever decrease in size due to a garbage collection.
     

  • Images – Decoded image data. Most often this corresponds with the images visible in the viewport.

  • Layers – Graphics layer data. This includes WebKit’s tile grid, page content using compositing layers, and any other layers the engine may make as an implementation detail.

  • Page – All other memory. This includes engine memory related to the DOM, styles, rendering data, memory caches, system allocations, etc.

We feel that these categories give a good overview of most memory used in a webpage. In some pages Layers and Image data will be the largest categories, but on others the JavaScript heap may be larger. Having this breakdown gives you a place to start for investigating spikes and growth.

Peak Memory Comparison

When investigating memory spikes, the Max Comparison memory chart can be useful. After selecting a specific time range at the top, you can see how the total memory usage at the end of the selection compares to the peak memory seen during the recording. The timeline will also include markers when apps receive memory pressure events.

Once you have the breakdown, you have an idea of where to look to make reductions. For large Image data, inspect your Image resources. To debug Layer data, use Web Inspector to enable Layer Borders to highlight the visible content on the page that uses compositing layers. For inspecting the JavaScript heap, we have the new JavaScript Allocations timeline. Before we look at this new timeline, let’s refresh our understanding of JavaScript object lifetimes.

JavaScript Leaks

JavaScript is a garbage collected language. As objects are created and modified, the engine automatically allocates any necessary memory for the objects. Once an object is no longer referenced, the engine can reclaim (“collect”) the memory allocated for that object.

To determine if an object should be kept alive or collected, the engine has to check if the object is reachable from a set of root objects. The window object in a webpage is a root object. The engine may have its own internal list of other root objects. JavaScriptCore includes a conservative garbage collector, so it treats any address on the stack that points to a heap allocated object as a root.

By following references from these root objects to other objects, and recursively on to objects they reference, the engine can mark all of the objects that are reachable (“live”), and should be kept alive. At the end, all of the objects in the heap that are not marked are unreachable (“dead”) and can be collected.

JavaScript applications will grow in memory as new objects are created and referenced. A memory leak occurs when objects that are no longer needed are still referenced, causing their memory to not be released. In JavaScript this can happen unintentionally if application logic fails to clear a reference to an object that is no longer needed.

Many leaks may be obvious once pointed out. For example, in this snippet a global variable holds onto a NodeList and will be kept alive:

function addClickHandlers() {
    paragraphs = document.querySelectorAll("p");
    for (let p of paragraphs)
        p.addEventListener("click", () => console.log("clicked"));
}

addClickHandlers();

The NodeList in paragraphs is not needed after the function returns, but is leaked because it accidentally created a global variable window.paragraphs. Simple errors, like accidentally creating a global variable here, can be caught by using strict mode JavaScript. However, the same pattern can be less obvious:

class ElementDebugger {
    constructor() { this.enabled = false; }

    enable() { this.enabled = true; }
    disable() { this.enabled = false; }

    addElements(selector) {
        this.elements = document.querySelectorAll(selector);
        for (let elem of this.elements) {
            elem.addEventListener("click", (event) => {
                console.log("clicked", elem);
                if (this.enabled)
                    debugger;
            });
        }
    }
}

let paragraphDebugger = new ElementDebugger();
paragraphDebugger.addElements("p");
paragraphDebugger.enable();

In this example, we want the paragraphDebugger global object to be kept alive so that we can enable or disable it whenever we want. However, the elements NodeList may unintentionally be kept around. To avoid the leak here, we could have made a local variable for the list with let elements, or explicitly cleared the reference when it is determined to not be needed anymore, with this.elements = null or this.elements = undefined.

NOTE: It may be tempting to use the delete operator, but that can introduce its own performance penalties. For named properties on an object, delete should be avoided in favor of just setting the property to null or undefined.

The above examples included explicit direct references to objects (variables and object properties). However, data referenced by a closure is not explicit, and it is easy to encounter situations where objects are unnecessarily captured in closures and contribute to memory growth:

class MessageList {
    constructor() { this.messages = []; }
    addMessage(xhr) {
        this.messages.push({
            text() { return xhr.responseText; }
        });
    }
}

window.messageList = new MessageList();

// Add messages from completed XHRs.
messageList.addMessage(xhr1);
messageList.addMessage(xhr2);

In this example, the leak is not as obvious. In addMessage we add an object to our list of messages. Each message has a text method which will get the text for that message. However, we created this method as a closure function() { return xhr.responseText; }. This function captures xhr, so the complete XMLHttpRequest object is being retained by this closure even though we only need a small portion of its data. This is unnecessarily wasteful.

Even worse, this XMLHttpRequest can have event listeners that it retains, and those event listeners may also be closures that retain even more objects! All this, when all we need to retain is just the text. To avoid retaining the XMLHttpRequest in this example, we can just avoid capturing it in our closure, and we can instead just keep the data we need:

addMessage(xhr) {
    let messageText = xhr.responseText;
    this.messages.push({
        text() { return messageText; }
    });
}

For many webpages small memory growth is not problematic. The page will use a bit of extra memory, but when the user navigates it will get cleaned up. Memory growth becomes a much bigger problem with long running JavaScript applications. As small to medium memory leaks build up over time, the application’s performance can start to degrade. Ultimately the memory footprint may reach the limits of memory-constrained devices and cause a crash.

JavaScript Allocations Timeline

The JavaScript Allocations Timeline gathers snapshots of the JavaScript heap which can then be analyzed. The timeline takes a snapshot at the start of recording, periodically during the recording, and at the end of recording. You can also use the button in the timeline’s navigation bar or call console.takeHeapSnapshot(<label>) in your code.

Snapshot List

A heap snapshot performs a full garbage collection and builds a graph of nodes (the live JavaScript objects) and directed edges (the references between the nodes). Node data includes some basic information about the object: a unique identifier, type, and size. Edge data lets us later know exactly how this object was kept alive, so we record a name for the edge that will be useful when displaying this path. For example if the edge was an object property we would record the property name, or if it is a captured closure variable we record the name of the variable.

The snapshot itself does not retain any JavaScript objects. This is important for detecting leaks; you want to allow objects to get collected, so that later you can identify the leaked objects which were not collected.

When you drill into an individual snapshot, we provide a few different views that let you explore and inspect. There is the Object Graph view, which allows you to explore the heap from a set of root objects, namely Window objects. Then there is the Instances view, which groups objects by class. Because we are connected to the live page, if a particular object is still alive we can provide a preview of the object and you can even log the value to Web Inspector’s console and interact with the object directly. Collected objects are removed from the top level of the Instances view.

JavaScript Allocations Instances View

The Instances view is where you will spend most of your time, because it gives you quick access to any object no matter how deep or complex the path to the object may be. Its categorization also makes it easy to recognize potential issues. For example, if you notice that there are multiple XMLHttpRequest or Promise instances but you didn’t expect any such objects to exist, you can immediately investigate them. This view is also ideal for sorting by size, allowing you to quickly focus on the largest objects in a snapshot, which saves analysis time in the case of a group of leaked objects where the larger objects are often the root causes of the leaks.

When expanding an instance, you see the other objects it references. Explicit references, such as a property name or array index, will have a name. Implicit or internal references, such as a closure retaining variables defined in an enclosing scope, will not have a name.

Each instance has two sizes. A self size and a retained size. The self size is only the size of the individual instance. This is normally very small, enough to hold the object’s state. It can be larger for strings and certain system objects representing compiled code. The retained size is the size of the object plus the size of all of the nodes it dominates (the objects that this particular object solely keeps alive). An easy way to think about the retained size is if the object were to be deleted right now, the retained size would be the amount of memory that would be reclaimed. The Mozilla Developer Network (MDN) provides an excellent description of dominators in JavaScript.

After creating a few objects like so:

class Person {
    constructor(name) {
        this.name = name;
    }
}

class Group {
    constructor(...members) {
        this.members = members;
    }
}

let shared = new Person("Shared");
let p1 = new Person("Person 1");
let p2 = new Person("Person 2");
let p3 = new Person("Person 3");    
p1.parent = p2.parent = p3.parent = shared;

let group = new Group(p1, p2, p3);

We can find the group object instance, expand it and see the objects it immediately dominates (members array), and if we keep expanding see the other objects it dominates (p1, p2, p3, shared) that ultimately contribute to its total retained size.

Retained Size

Shortest Path to Instance Popover

Perhaps the most powerful aspect of the memory tools is being able to determine the path to a particular object, so you can reason about what keeps it alive. When you hover the instance’s unique identifier, you get a popover showing the shortest path from a root to that instance. If you suspect an object should have gone away, this path will be invaluable for understanding why the object is kept alive.

You can click the unique identifier to log the live value to the console so that you can interact with it directly. Also, for functions, you can click the goto arrow to jump directly to the function declaration.

Detecting JavaScript Leaks

Heap snapshot comparisons are an effective technique for detecting leaks and unintended memory growth. The technique is often referred to as generational analysis. Analyzing an individual heap snapshot for leaks would be time consuming, and on pages with a large number of objects, small leaks would be hard to spot. This is where comparisons shine, letting you focus in on just the objects created between two points in time.

Generational analysis works best when comparing two snapshots before and after an operation that you expect to be memory neutral or have minimal growth. For example, showing and hiding a section of the page, creating and deleting a comment, toggling a preference on and off. You would not expect these actions to cause large memory growth. But if you perform them repeatedly and they do, then comparing a snapshot from before and after the operation would reveal created objects that have not been collected and may be leaks.

Put simply, the steps are:

  1. Get your web application into a steady state.
  2. Start recording JavaScripts Allocations Timeline.
  3. Perform actions that are expected to be memory neutral. Take a snapshot each repetition.
  4. Stop recording.

It is best to repeat the action multiple times and end up with multiple snapshots. Often applications populate caches the first time an operation is performed, or just as likely the JavaScript engine itself may create its own internal objects early on. If you perform the action five times and memory only increased the first time, then there likely isn’t a problem, but if you saw a steady increase each time, then you’ve likely uncovered a leak. This style of analysis works great with console.takeHeapSnapshot() because it makes it easy to control the exact before and after points.

To compare two snapshots start at the snapshot list. Click the Compare button, select a baseline snapshot (before) and comparison snapshot (after) and you get the familiar Instances view for the comparison. The comparison shows only the objects created within that time range that are still alive.

Playing with the example above, it is easy to see that multiple XMLHttpRequest objects are kept alive, see that it is a closure keeping them alive, jump to the function capturing them, and address the issue.

Snapshot Comparison
Snapshot Comparison
Snapshot Comparison

Implementation Details

Exposing all of the objects in JavaScriptCore’s heap reveals internal, engine allocated, objects in the heap. These appear as nodes without a preview with names like Structure and FunctionExecutable. We felt it was useful to include these objects to accurately show how they contribute to the retained size of the actual objects exposed to the page. However, keep in mind that their names, and even their existence, is entirely an internal implementation detail that may change. For this reason, the Instances view filters out such objects from the top level categories, allowing you to focus on only the objects you have control over.

JavaScriptCore Internal Objects

In JavaScriptCore, primitive values like numbers and booleans are not allocated as heap objects. Hence, they will not show up in any snapshots. Instead, they are stored as encoded values in JavaScript objects. The string primitive, on the other hand, is allocated as a heap object, and will show up in snapshots. You can always log a live value to the console and see all of its properties and values.

We took great effort in keeping the memory and performance costs of snapshots to a minimum. After all, if you are debugging a memory issue you don’t want the memory tools introducing more memory pressure. However, you should be aware that debugging both memory and performance at the same time won’t be as accurate as measuring either of them individually. Web Inspector has the ability to let you turn on and off individual timelines to get the most accurate recording possible.

Like other potentially expensive console APIs, console.takeHeapSnapshot does nothing unless Web Inspector is open. That said, it is always best practice to avoid including unnecessary debug code in production.

Feedback

You can try out the new Memory Timelines in the latest Safari Technology Preview. Let us know how they work for you. Send feedback on Twitter (@webkit, @JosephPecoraro) or by filing a bug.

Note: Learn more about Web Inspector from the Web Inspector Reference documentation.
肾的主要功能是什么 孔子姓什么名什么 黄花菜都凉了是什么意思 肠道炎有什么症状 2月16日什么星座
牙龈萎缩吃什么药见效快 狗喜欢吃什么食物 屁股痛是什么引起的 黑海为什么叫黑海 口甲读什么
胃不好能吃什么 ug是什么单位 泥丸宫在什么位置 小腿肌肉痛什么原因 三叉神经痛看什么科
脾虚是什么原因引起的 肺部散在小结节是什么意思 耳石症眩晕吃什么药 血压高吃什么降压药 炒菜用什么油好吃又健康
塬字五行属什么dajiketang.com cbd是什么hcv9jop6ns0r.cn 晕车喝什么饮料luyiluode.com 无锡有什么好玩的huizhijixie.com 脊膜瘤是什么样的病hcv9jop7ns9r.cn
互粉是什么意思hcv9jop2ns8r.cn 戾气重是什么意思hcv7jop9ns0r.cn 水满则溢月盈则亏是什么意思bysq.com 五石散是什么1949doufunao.com 意思是什么意思hcv7jop4ns7r.cn
腿浮肿是什么原因hcv8jop5ns3r.cn 内痔有什么症状与感觉hcv8jop2ns2r.cn 养鱼为什么养单不养双hcv7jop6ns7r.cn 响屁多是什么原因hcv8jop8ns2r.cn 体外是什么意思hcv9jop1ns8r.cn
小王子讲了什么故事xscnpatent.com 印记是什么意思creativexi.com 无期徒刑是什么意思sscsqa.com 女人辟邪带什么最好hcv9jop4ns3r.cn 天安门以前叫什么hcv7jop9ns5r.cn
百度