关于JavaScript闭包/匿名函数,以及垃圾回收算法的小结

来源:互联网 发布:淘宝商品sku设置规则 编辑:程序博客网 时间:2024/05/13 18:18

未完待续,长时间更新

js和java垃圾回收


写博客总得有个发起点,或者说源头?那么今天的源头就从上面这张图片讲起。

为什么会贴这张图呢?因为它今天出现了两次,分别出现在《深入理解java虚拟机,高级特性与最佳实践》和《JavaScript高级程序设计》两本书中。事关两本经典书籍且有两门主流语言有联系,还涉及垃圾回收与内存泄漏,所以对它印象深刻嘛。

不难看出这是一个js函数。函数创建了两个对象,并且让彼此相互引用。首先谈java,这个函数可以用java语言完美复制没问题吧(如下图)。在java语言的垃圾回收算法中,发现并标记无用的“垃圾”–即未被引用的对象,是回收的第一步,如果“垃圾”都找不到……那你回收个毛啊?所以要怎找垃圾呢?

直接计数算法

简言之,每一个对象都有一个初始值(暂且美名曰“被引用值”)为0,每被引用一次这个值就加一,每解除一次引用这个值就减一。故当垃圾回收器要开始垃圾回收时,它就可以通过扫描每一个被引用值,来判断这个值还有没有被引用着,也就是“标记”。这种方式看似很简洁很完美,然后bug来了,如下图或所示:当两个新建对象产生互相引用时,将导致两个对象的引用计数都不为零,从而导致gc没办法回收他们。这个bug被称为引用计数算法的缺陷,然后事实上gc却收集了这两个对象,为什么呢?因为java没用引用计数算法,而是用的可达性分析算法。

可达性分析算法,即通过一个GCroot根结点搜索所有对象,所走过的路径成为引用链。和GCroot不再相联的对象,将被标记为可回收的对象。这种算法解决了引用计数算法的bug,但是当引用对象很多时,搜索不可达对象必然会带来而外的系统开销。

再谈JavaScript,为了解决引用计数算法带来的问题,js采用了标记清除算法。注意,这里的标记清楚算法与java的标记清除算法有细微的区别:js的标记指的是对那些离开了执行环境的对象进行标记,而java的标记是指,首先通过可达性分析证实无法的到达的对象,然后再标记。js的标记清除算法既包含无用对象的查找,而java的标记清除并不包含这一过程,它真的就只是标记一下!

前端boostrap小结

  1. width使用百分制,保证了横向缩放比。
  2. 父级元素无表框导致子元素margin-top传递到父级元素,使用父级元素padding-top解决
  3. 父级元素的text-aligin:center和子元素的margin-left/right 保证了元素的居中显示,且是一种一般用法
  4. html页面使用按序解析的方式,故而引入js css要置于自己编写的cssjs之前,方便覆盖。
  5. boostrap的栅格系统很强大

JavaScript特性分析

JavaScript特性,由于对java较为熟悉,所以就相对java来谈了。java和JavaScript最大的不同即在于一个是强类型语言一个弱类型语言。所以泛泛而谈,JavaScript也就拥有了所有弱类型语言相对强类型语言的特征。

1.变量,JavaScript的变量是松散的。它的变量声明只是相当于一个占位符,并不会声明类型,因此你可以把五大数据类型(String,Number,Boolean,Object,Function)中的任何一种赋值一个var。

2.Undefine(包括NAN–非数值,null–空引用),弥补未初始化的强类型检查。事实上,java也可以不赋初值就直接使用的,这是依赖于java的对象创建过程中的内存分配机制。在java new一个对象的过程中,首先是类的加载检查,然后进行内存分配。分配过程有两种分式,如果有整块的内存就使用”指针碰撞“的方式,如果只有零碎的内存就使用”空闲列表法“。无论哪种分式在大量频繁的对象创建过程中都不能保证线程安全,所以,TLAB横空出世,当当当!Thread Local Allocation Buffer 本地线程分配缓存,保证每一个线程在java堆中都会预先留出一小块内存,以此就能保证线程安全的进行内存分配。内存分配完成后,或者TLAB分配完成后,虚拟机将内存空间初始化为零值。这一步操作保证了对象的实例字段不赋处置就可以直接使用。

3.在上述两点的前提下,JavaScript可以对任何类型进行操作和运算。其中操作过程使用到不同类型的数据,就进行类型转换(toStrign(),toLocalString()),或者得到一个极大值Infinity,未知值NAN.

4.函数,js中的函数并不是java意义上的函数。js的函数,都是对象。且js函数的参数列表是不固定数量的,对于一个有三个参数的函数,传入一个函数可以执行,传入两个三个也可以执行。背后的机理是:每一个function对象的参数列表都是依靠一个arguments数组进行维护的,也就是说无论你传入多少个参数,最终传递给函数的,都只是一个arguments数组,所有的参数都只是arguments的一个成员。这种任意参数的函数方式,某种程度上弥补了js没有函数重载的遗憾。此外,js函数可以动态增加属性,可以通过arguments动态增加删除属性也是js的重要特征。

5.作用链和执行环境。
 执行环境有全局执行环境(也称为全局环境)和函数执行环境之分;
 每次进入一个新执行环境,都会创建一个用于搜索变量和函数的作用域链;
 函数的局部环境不仅有权访问函数作用域中的变量,而且有权访问其包含(父)环境,乃至全
局环境;
 全局环境只能访问在全局环境中定义的变量和函数,而不能直接访问局部环境中的任何数据;
 变量的执行环境有助于确定应该何时释放内存

6待补充