本地储存和垃圾回收机制(内存管理)

前言

今天在慕课网学习时,谈到了本地存储的知识(主要是Cookie和Storage),下面将总结一下相关知识点。

基本概念

Cookie是在HTTP协议下,服务器或脚本可以维护客户工作站上信息的一种方式。由Web服务器保存在用户浏览器(客户端)上的小本文文件。它可以包含有关用户的信息。比如你登录某个网站市场可以看到“记住密码”,这通常就是通过在 Cookie 中存入一段辨别用户身份的数据来实现的。目前有些 Cookie 是临时的,有些则是持续的。

另外cookie还需要指定作用域,不可以跨域调用。

优势
具有极高的扩展性和可用性
1.通过良好的编程,控制保存在cookie中的session对象的大小。
2.通过加密和安全传输技术,减少cookie被破解的可能性。
3.只有在cookie中存放不敏感的数据,即使被盗取也不会有很大的损失。
4.控制cookie的生命期,使之不会永远有效。这样的话偷盗者很可能拿到的就是一个过期的cookie。

缺点
1.cookie的长度和数量的限制。每个domain最多只能有20条cookie,每个cookie长度不能超过4KB,否则会被截掉。

2.安全性问题。如果cookie被人拦掉了,那个人就可以获取到所有session信息。加密的话也不起什么作用。

3.有些状态不可能保存在客户端。例如,为了防止重复提交表单,我们需要在服务端保存一个计数器。若吧计数器保存在客户端,则起不到什么作用。

Web Storage

实际上由两部分组成:sessionStoragelocalStorage

sessionStorage 用于本地存储一个会话(session)中的数据,这些数据只有在同一个会话中的页面才能访问并且当会话结束后(页面关闭)数据随之销毁。因此sessionStorage是一种持久化的本地存储,仅仅是会话级别的存储。

localStorage 是 HTML5 标准中新加入的技术,用于持久化的本地存储,除非主动删除数据,否则数据是永远不会过期的。

优势
存储空间
存储空间 更大:IE8下每个独立的存储空间为10M,其他浏览器实现略有不同,但都比Cookie要大很多。

接口
更多丰富易用的接口:Web Storage提供了一套更为丰富的接口,使得数据操作更为简便。
服务器
存储内容不会发送到服务器:当设置了Cookie后,Cookie的内容会随着请求一并发送的服务器,这对于本地存储的数据是一种带宽浪费。而Web Storage中的数据则仅仅是存在本地,不会与服务器发生任何交互。

存储空间
独立的存储空间:每个域(包括子域)有独立的存储空间,各个存储空间是完全独立的,因此不会造成数据混乱。

三种方法比较

特性 cookoe localStorage sessionStorage
数据生命周期 一般由服务器生成,可设置失效时间。如果在浏览器端生成Cookie,默认是关闭浏览器后失效 除非被清除,否则永久保存 仅在当前会话下有效,关闭页面或浏览器后被清除
存放数据大小 4k左右 一般为5MB ← 同左
与服务器端通信 每次都会携带在HTTP头中,如果使用cookie保存过多数据会带来性能问题 仅在客户端(即浏览器)中保存,不参与和服务器的通信 ← 同左
易用性 需要程序员自己封装,源生的Cookie接口不友好 源生接口可以接受,亦可再次封装来对Object和Array有更好的支持 ← 同左

应用

因为考虑到每个 HTTP 请求都会带着 Cookie 的信息,所以 Cookie当然是能精简就精简啦,比较常用的一个应用场景就是判断用户是否登录。针对登录过的用户,服务器端会在他登录时往 Cookie中插入一段加密过的唯一辨识单一用户的辨识码,下次只要读取这个值就可以判断当前用户是否登录啦。

而另一方面 localStorage 接替了 Cookie 管理购物车的工作,同时也能胜任其他一些工作。比如HTML5游戏通常会产生一些本地数据,localStorage 也是非常适用的。如果遇到一些内容特别多的表单,为了优化用户体验,我们可能要把表单页面拆分成多个子页面,然后按步骤引导用户填写。这时候 sessionStorage 的作用就发挥出来了。

安全性的考虑

需要注意的是,不是什么数据都适合放在 Cookie、localStorage 和 sessionStorage 中的。使用它们的时候,需要时刻注意是否有代码存在 XSS 注入的风险。因为只要打开控制台,你就随意修改它们的值,也就是说如果你的网站中有 XSS 的风险,它们就能对你的 localStorage 肆意妄为。所以千万不要用它们存储你系统中的敏感数据。

cookie的作用是与服务器进行交互,作为HTTP规范的一部分存在,而web storage仅仅是为了在本地存储数据而生。

垃圾回收机制

原理

垃圾收集器会定期(周期性)找出没有数据并释放,回收内存。

标识无用数据的策略

标记清除
javascript中最常用的垃圾回收方式。当变量进入环境时,将这个变量标记为“进入环境”。当变量离开环境时,则将其标记为“离开环境”。标记“离开环境”的就回收内存。

工作流程:
1.垃圾回收器,在运行的时候会给存储在内存中的所有变量都加上标记。
2.去掉环境中的变量以及被环境中的变量引用的变量的标记。
3.再被加上标记的会被视为准备删除的变量。
4.垃圾回收器完成内存清除工作,销毁那些带标记的值并回收他们所占用的内存空间。

1
2
3
4
5
function test(){
var a = 10 ; //被标记 ,进入环境
var b = 20 ; //被标记 ,进入环境
}
test(); //执行完毕 之后 a、b又被标离开环境,被回收。

引用计数
另一种不太常见的垃圾回收策略是引用计数。引用计数的含义是跟踪记录每个值被引用的次数。

工作流程:
1.声明了一个变量并将一个引用类型的值赋值给这个变量,这个引用类型值的引用次数就是1。
2.同一个值又被赋值给另一个变量,这个引用类型值的引用次数加1.
3.当包含这个引用类型值的变量又被赋值成另一个值了,那么这个引用类型值的引用次数减1.
4.当引用次数变成0时,说明没办法访问这个值了。
5.当垃圾收集器下一次运行时,它就会释放引用次数是0的值所占的内存。

1
2
3
4
5
6
7
function test(){
var xm = {} ; //xm的引用次数为1
var xh = {} ; //xh的引用次数为1
}
test();
xm = null; // 0
xh = null; // 0

当循环引用,无法被回收。

1
2
3
4
5
6
7
8
9
10

function test(){
var xm = {} ; //xm的引用次数为1
var xh = {} ; //xh的引用次数为1
xm.wife = xh; //xh的引用次数为2
xh.husband = xm; //xm的引用次数为2
}
test();
xm = null; // 1
xh = null; // 1

原因:IE9之前的浏览器里的BOM和DOM并不是原生的。通过C++在COM的基础上实现的,而COM使用的就是引用计数的回收机制。

1
2
3
4
var element = document.getElementById("some_element");
var myObj =new Object();
myObj.element = element;
element.someObject = myObj;

上面的代码,一个DOM元素(element)与一个原生JavaScript对象(myObj)之间建立了循环引用。其中,变量myObj有一个名为element的属性指向element;而变量element有一个名为someObject的属性回指到myObj。由于循环引用,即使将例子中的DOM从页面中移除,内存也永远不会回收。

解决方法
手动解除变量引用,可以消除循环引用现象。

1
2
myObj.element = null;
element.someObject =null;

内存管理

分配给Web浏览器是少于桌面应用程序的内存,主要是出于安全方面的考虑。防止浏览器占用过多的内存,导致应用程序崩溃。确保占用少的内存,可以让页面获得更好的性能。

优化内存最佳方式:只保留内存有用的数据,立即释放无用数据。

释放内存的方法就是设置为 null,解除引用。适合于大多的全局变量。因为局部变量离开作用域的时候,会自动解除引用。


深入理解回收机制,可以阅读此文:JavaScript垃圾回收机制
部分信息来源:咀嚼之味