project中的堆栈内存,内存地址引用,gc相关问题

项目中遇到了关于js内存,引用类型,gc机制相关的问题,记录下来。
首先复现一下代码:

const option = {
  yAxis: [{
    type: 'value',
    ......  
  }]
};
option.yAxis.push(option.yAxis[0]);
option.yAxis[0].min = 1;
option.yAxis[1].min = 2;

发现option.yAxis下面的min的值都是2;第一反应是以为之前的代码写的有问题,所以打断点,打日志,发现都正常,然后想到了有可能是内存指针导致的,然后可以做以下两种修改。

const option = {
  yAxis: [{
    type: 'value',
    ......  
  }]
};
option.yAxis.push(JSON.parse(JSON.stringify(option.yAxis[0])));
option.yAxis[0].min = 1;
option.yAxis[1].min = 2;

或者

const option = {
  yAxis: [{
    type: 'value',
    ......  
  }]
};
option.yAxis.push(option.yAxis[0]);
option.yAxis[0] = {min: 1};
option.yAxis[1] = {min: 2};

以上两种写法都可以规避内存指针引用导致的数据问题。

剖析以下问题的本质吧:

  1. JS基本数据类型:Null,Undefined,Number,Boolean,Symbol,String
  2. JS复杂数据类型:Object Array (也算是object)

当我们在代码里面:

var num = 123;
var obj = { name: 'obj' };
var obj_copy = obj;

此时会开辟两块内存空间,一个存储123,一个存储 { name: 'obj' }; 其中是num的指针会直接指向栈内存中的123,obj的指针会指向堆内存中的 { name: 'obj' },obj_copy的引用指针会存放在栈内存中;
如果我们编辑以下代码:

var num = 123;
var obj = { name: 'obj' };
var obj_copy = obj;
obj.name = 'xxx';

那么我们会发现obj_copy的name也会变成xxx,其实就是因为产生了指针以引用,指向的是同一块内存空间;
如果编辑以下代码:

var num = 123;
var obj = { name: 'obj' };
var obj_copy = obj;
obj = {name: 'xxx'};

那么我们会发现obj_copy的name还是obj,这是因为obj = {name: 'xxx'};会产生一块新的内存空间,然后obj会产生一次引用,obj_copy的引用跟该引用没有任何毛线关系。那么我们项目中的问题就迎刃而解了。

写到这里,突然想到了es6 的const 变量申明:

const  object = { name: 'object'};
const num = 5;
object.name = 'new_object';
num = 4;

我们会发现object的name确实变成了字符串new_object,但是num=4会报错,为什么呢?其实这个问题跟堆栈内存没有关系,还是跟引用数据类型有关;
看下面的代码:

let numA = 1;
let numB = numA;
numA = 2;
console.log(numB );

我们发现numB的值仍然是1,其实基本数据类型也是存在引用的,只是基本数据类型无法像object一样去更改某个key的值而已,就比如一座房子和一把板凳,如果你改变了房子或者凳子,那么他就是实实在在地改变了,如果你只是改变了一座房子内部的一部分,它仍然是房子。

说到这里,不得不提一下es6的 WeekMap了(也是借用了阮大的例子吧,哈哈哈!)

const wm = new WeakMap();
const element = document.getElementById('example');
wm.set(element, 'some information');
wm.get(element) // "some information"

WeekMap 是一种弱引用,也就是说,该节点的引用计数是1,如果element设置为null,Weakmap 保存的这个键值对,也会自动消失。

说到这里,就要说一下javascript的垃圾回收机制了,分为两种类型吧,一种是标记清除 ,一种是引用计数。

let fn = function (){
  let a = 1;
  return a;
}
fn();

在执行fn函数时,变量a被标记为进入环境,在函数没有被执行结束之前,是不能释放该变量所指向的内存的,当函数执行完之后,变量会被标记为离开环境,则会被gc回收

let fn = function (){
  let a = 1;
  return a;
}
let back = fn();

如果代码写成这样的话,变量a所占用的内存是不会被gc的,因为在外部存在了引用,虽然a已经离开了fn的执行环境,但是a的引用计数是2,所以不会被gc回收清除。

function problem(){     
    var objectA = new Object();
    var objectB = new Object(); 

    objectA.someOtherObject = objectB;
    objectB.anotherObject = objectA; 
} 

上述情况也是objectA 和B都离开了函数环境,但是因为存在循环引用,所以引用计数都不为0,所以内存就不会得到回收,在个别情况下,需要手动回收。
另外,gc时,会阻塞主线程,所以平常写代码的时候一定要注意相关问题,务必规避内存泄漏的相关问题。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 195,898评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,401评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,058评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,539评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,382评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,319评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,706评论 3 386
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,370评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,664评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,715评论 2 312
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,476评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,326评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,730评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,003评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,275评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,683评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,877评论 2 335

推荐阅读更多精彩内容