前端面试题之第七弹

一、哪些操作会造成内存泄漏

——在了解什么操作会造成内存泄漏之前我们先了解一下什么是内存泄漏吧

什么是内存泄漏:
内存泄漏是指一块被分配的内存既不能使用,又不能回收,直到浏览器进程结束。浏览器中采用自动垃圾回收方法管理内存,但由于浏览器垃圾回收方法有bug,因此会产生内存泄漏。

——那么疑点又来了,什么是回收机制呢,别急,我们往下看

js垃圾回收机制—GC:
Javascript具有自动垃圾回收机制(GC:Garbage Collecation),也就是说,执行环境会负责管理代码执行过程中使用的内存。
Javascript垃圾回收的机制很简单:找出不再使用的变量,然后释放掉其占用的内存,但是这个过程不是实时的,因为其开销比较大,所以垃圾回收系统(GC)会按照固定的时间间隔,周期性的执行。
到底哪个变量是没有用的?所以垃圾收集器必须跟踪到底哪个变量没用,对于不再有用的变量打上标记,以备将来收回其内存。用于标记的无用变量的策略可能因实现而有所区别,通常情况下有两种实现方式:标记清除和引用计数。引用技术不太常用,标记清除较为常用。

标记清除:
js中最常用的垃圾回收方式就是标记清除,当变量进入环境时,例如,在函数中声明一个变量,就将这个变量标记为“进入环境”。从逻辑上讲,永远不能释放进入环境的变量所占用的内存,因为只要执行流进入相应的环境,就可能会用到它们。而当变量离开环境时,则将其标记为“离开环境”

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

引用计数:
引用计数的含义是跟踪记录每个值被引用的次数。当声明了一个变量并将一个引用类型值(function object array)赋给该变量时,则这个值的引用次数就是1。如果同一个值又被赋给另一个变量,则该值的引用次数加1。相反,如果包含对这个值引用的变量又取得了另外一个值,则这个值的引用次数减1。当这个值的引用次数变成0时,则说明没有办法再访问这个值了,因而就可以将其占用的内存空间回收回来。这样,当垃圾回收器下次再运行时,它就会释放那些引用次数为0的值所占用的内存。

function test(){
		   var a = {};//a的引用次数为0
		   var b = a; //a的引用次数加1,为1
		   var c = a; //a的引用次数再加1,为2
		   var b = {};//a的引用次数减1,为1
	   }

——什么是内存泄漏相信大家也了解的差不多了,现在我们回归正题,js哪些操作会造成内存泄漏?

虽然JavaScript会自动垃圾收集,但是如果我们的代码写法不当,会让变量一直处于“进入环境”的状态,无法被回收。下面列一下内存泄漏常见的几种情况。

  1. 意外的全局变量引起的内存泄漏
function leaks(){
		   leak = 'xxxxx'; //leak成为一个全局变量,不会被回收
	   }

—你可以通过加上 ‘use strict’ 启用严格模式来避免这类问题, 严格模式会阻止你创建意外的全局变量.

  1. 闭包引起的内存泄漏
function bindEvent(){
		   var obj = document.createElement('p');
		   obj.onclick = function(){
			   //Even if it s a empty function
		   }
	   }

—闭包可以维持函数内局部变量,使其得不到释放。 上例定义事件回调时,由于是函数内定义函数,并且内部函数–事件回调的引用外暴了,形成了闭包 解决之道,将事件处理函数定义在外部,解除闭包,或者在定义事件处理函数的外部函数中,删除对dom的引用

  1. 将事件处理函数定义在外部
function onclickHandler(){
		   //do something
	   }
	   function bindEvent(){
		   var obj = document.createElement('p');
		   obj.onclick = onclickHandler;
	   }

二、进程与线程的区别

进程和线程是什么?
首先你要理解cpu的概念,计算机上的所有操作都是由cpu来执行的,cpu将要执行的操作分为一个个的任务,这些任务我们就可以理解为进程,而这些任务又分为一些细粒度更小的子任务,这些子任务就称作线程

cpu轮流执行任务的,每一个任务需要经过以下三个阶段:

  • 加载上下文
  • 执行
  • 保存上下文

也就是说,每一个进程从加载、执行、到切换下一个进程执行,都会经历同样的一个过程,我们的cpu就是在无时无刻地进行这样的进程切换操作

而我们又可以把进程分为一些细粒度更小的进程,这些线程之间也可以来回的切换,就像进程一样,但是却不需要加载和保存上下人的操作,因为这些线程都是共享上下文的。

进程与线程的区别:

  • 性质不同 进程是资源分配的基本单位,线程是cpu执行运算和调度的基本单位
  • 归属不同 一个操作系统中可以有很多进程,一个进程可以有很多线程
  • 开销不同 进程创建、销毁和切换的开销都要远大于线程
  • 拥有资源不同 进程之间可以通过管道、消息队列、共享内存、信号量、以及Socket等机制实现通信,线程之间主要通过共享变量以及其变种形式实现通信
  • 控制和影响能力不同 子进程无法控制父进程,一个进程发生异常时一般不会影响其他进程,子线程可以控制父线程,如果主线程发生异常,会影响其所在进程和其余线程
  • 扩展能力不同 多进程可以方便地扩展到多机分布式系统上,多线程想要扩展到多台机器上就很困难
  • cpu利用率不同 进程的cpu利用率低,因为需要额外的上下人切换开销,线程的cpu利用率高,因为切换简单
  • 可靠性不同 进程的可靠性要高于线程

三、eval是做什么的

在非严格模式,可以将json字符串转换为对象的形式。也可将字符串参数转化为脚本代码执行,但只适合在非严格模式下。它的功能是将对应的字符串解析成js并执行,应该避免使用js,因为非常消耗性能(2次,一次解析成js,一次执行),简单来说将字符串参数解析成js代码并执行,并返回执行结果。但应避免使用,不安全,也耗性能。
具体实现:

function sayhello(){}
function saygoodbye(){}
var f="sayhello";
eval(f+'()');//运行sayhello();
f='saygoodbye';
eval(f+'()');//运行saygoodbye();

未完待续…

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值