弱分代假设(The Weak Generational Hypothesis)

在 GC 的研究中有一个广为人知的现象,叫做弱分代假设(The Weak Generational Hypothesis),许多 GC 的研究者/开发者们观察到:

  • 大多数对象死的早
  • 那些死得不早的对象,通常倾向于永生

基于这个现象,许多垃圾回收器将对象进行分代,对生存周期长度不同的对象采用不同的垃圾回收算法。那些新分配的对象会得到更多的“关照”,检查它们是否已经无人引用可以回收。而那些多次检查后依然顽强生存下来的对象会被晋升到下一代,之后被检查的频率也会越来越低。这样,垃圾回收器可以尽快地回收掉大量短命的对象,节省了内存,又避免了频繁检查那些按照弱分代假设倾向于永生的老对象,节省了时间。

V8 的垃圾回收器也是基于弱分代假设将对象进行分代回收的一员,它将 JavaScript 对象分成了两代:新生代(new generation,或称 young generation)和老生代(old generation),大部分的新对象都诞生在新生代,使用拿空间换时间的 Scavenge 回收策略,快速回收内存。在新生代中经历了两次 GC 还没有被回收掉的对象,会在第二次回收时被晋升(promote)到老生代,老生代使用 Mark-Sweep-Compact 回收策略,在空间和时间中取得平衡,并减轻单纯的 Mark-Sweep 引入的内存碎片问题。因此在垃圾回收日志中,我们会看到一些 new,old,以及 promotion 相关的字段

浮点数相关的操作通常比整型操作要慢

虽然 ECMAScript 中没有规定整数类型,Number 都是 IEEE 浮点数,但是由于在 CPU 上浮点数相关的操作通常比整型操作要慢,大多数的 JavaScript 引擎都在底层实现中引入了整型,用于提升 for 循环和数组索引等场景的性能,并配以一定的技巧来将指针和整数(可能还有浮点数)“压缩”到同一种数据结构中节省空间。

map循环明显比 for循环、for in 、 forEach慢

原因?

NaN的原型链类型是[Object Number]

String类被设计成不可变(immutable)类,所以它的所有对象都是不可变对象。

例如:

String str = “hello”;

str = str + “world“;

所以当上文str指向了一个String对象(内容为“hello”),然后对str进行“+”操作,str原来指向的对象并没有变,而是str又指向了另外一个对象(“hello world”),原来的对象还在内存中。

由此也可以看出,频繁的对String对象进行修改,会造成很大的内存开销。此时应该用StringBuffer或StringBuilder来代替String。

而new String()更加不适合,因为每一次创建对象都会调用构造器在堆中产生新的对象,性能低下且内存更加浪费。

深拷贝的四种方式

  • clone (递归拷贝)
  • cloneJson (使用JSON.pase(JSON.stringify()))
  • cloneLoop (循环拷贝)
  • cloneForce (破解引用拷贝,如果存在循环引用,且需要保持引用)

jsmini

致力于为大家提供一组小而美,无依赖的高质量库

为什么 Javascript 操作 dom 会慢?

在浏览器中都是把DOM和JavaScript分开来实现的,dom和js是两座孤岛,访问需要成本

不要使用 table 布局,因为 table 中某个元素旦触发了 reflow,那么整个 table 的元素都会触发 reflow。

那么在不得已使用 table 的场合,可以设置 table-layout:auto; 或者是 table-layout:fixed 这样可以让 table 一行一行的渲染,这种做法也是为了限制 reflow 的影响范围

atob和btoa无法解析中文

可以解析中文
decodeURIComponent(encodeURIComponent(window.atob(str)))