内存回收机制

JS引擎V8的内存回收机制与内存限制(标记清除法)
原创真的137 最后发布于2019-03-12 13:48:37 阅读数 166 收藏
展开
在Node中通过JavaScript使用内存时会发现只能使用部分呢内存(64位下位1.4GB,32位系统下位0.7GB),这样的限制使得Node无法操作大内存对象。造成这个问题的原因在于Node基于V8构建,所以在Node中使用的JavaScript对象基本上都是通过V8自己的方式来进行分配和管理的。
在V8中,所有的JavaScript对象都是通过堆来分配的。当我们在代码中声明变量并赋值的时候,所使用的对象就会分配在堆中。如果已申请的堆空闲内存不够分配新的对象,将继续申请堆内存,直到堆的大小超过V8的限制为止。V8限制堆大小的原因在于V8的垃圾回收机制的限制。

V8的垃圾回收机制
V8主要的垃圾回收算法
V8的垃圾回收策略主要基于分代式垃圾回收机制
(ps:本文参考《深入浅出Nodejs》)
1、V8的内存分代
在V8中,主要将内存分为新生代和老生代。新生代中的对象位存活时间较短的对象,老生代中的对象为存活时间较长或者常驻内存的对象。
新生代和老生代的内存空间在一开始就是指定的。
2、Scavenge算法
在分代的基础上,新生代中的对象主要通过Scavenge算法进行垃圾回收。
Scavenge的具体实现中,主要采用了Cheney算法。

Cheney算法是一种采用复制的方式实现的垃圾回收算法。它将堆内存一分为二,每一部分空间成为semispace。在这两个semispace空间中,只有一个处于使用中,另一个处于闲置状态。处于使用状态的semispace空间叫做From空间,处于闲置状态的semispace空间叫to空间。当我们分配对象的时候,先从From空间空间中进行分配。当开始进行垃圾回收的时,会检查From空间中的存活对象,这些存活对象将被复制到To空间中,而非存活对象占用的空间将会被释放。完成复制后,From和To空间的角色发生对换。

简而言之,就是通过将存活对象在两个semispace空间之间进行复制。
从前面的机制来看,Scavenge是一种牺牲空间换时间的算法,所以无法大规模地应用到所有的垃圾回收中,但是Scavenge非常使用对象生命周期比较短的场景也就是适合用在新生代中。

实际上的堆内存是新生代的两个semispace空间大小和老生代所使用内存大小之和

当一个对象经过多次复制仍然存活的时候,它就会被认为是身影周期比较长的对象,这种生命周期比较长的对象随后会被移动到新生代中,采用新的算法进行管理。从新生代到老生代的过程成为晋升。

对象晋升的两个条件

对象是否经历过Scavenge回收(通过检测内存地址是否改变)
对象从From空间中复制到To空间中时,先判断这个对象是否经历过一次Scavenge回收,如果经历过,会从From空间复制到老生代空间,如果没有经历,则复制到To空间。
To空间的内存占用比是否超过闲置
当一个对象从From空间复制到To空间时候,如果To空间使用率超过25%,则将该对象直接晋升到老生代中
设置25%是因为当Scavenge回收结束之后,T空间会变成From空间,接下俩的内存分配会在这个空间进行,如果占比过高,会影响后续的内存分配
3、Mark-Sweep & Mark-Compact
老生代采用Mark-Sweep & Mark-Compact而不采用Scavenge算法的原因:采用Scavenge会导致再一半的空间浪费,第二是存活对象较多,复制存活对象的效率将会很低.
Mark-Sweep是标记清除的意思,它分为标记和清除两个阶段。Mark-Sweep在标记阶段遍历堆中所有对象,并标记活着的对象,在随后的清除阶段中,只清除没有被标记的对象。可以看出,Scavenge只复制活着的对象,而Mark-Sweep只清除死亡对象。活对象在新生代中只占较小部分,死对象在老生代中只占较小部分,这是两种回收方式能高效处理的原因。

Mark-Sweep的最大问题在于一次标记清除之后,内存空间会出现不连续的状态,这种内存碎片会对后续的内存分配造成问题,当无法完成此次分配的时候,就会触发一次垃圾回收。

Mark-Compact是为解决Mark-Sweep内存碎片提出来的。Mark-Compact是标记的意思。他们的差别在与标记为死亡后,在整理的过程中,将活着的对象往一端移动,移动完成后,移动完成后,直接清除掉边界的内存。

Mark-Sweep和Mark-Compact这两种策略是递进关系,但是在V8中两者是结合使用的。

垃圾回收造成的停顿
垃圾回收的这三种算法都需要将应用逻辑暂停下来,待执行完垃圾回收后再恢复执行应用逻辑。当v8的分代式垃圾回收中,新生代造成的停顿比老生代造成的停顿少的多。为了减少这种影响,引入了增量标记、延迟标记、增量式整理等。计划引入并行标记和并行处理。

V8对内存闲置的设置对于Chrome浏览器这种选项卡页面使用一个V8实例来说,内存的使用是绰绰有余的,而对Node编写的服务端来说,内存闲置也不影响正常场景下的使用。想要高性能的执行效率,注意让垃圾回收尽量少地进行。

以Web服务器中的会话实现为例,一般通过内存来存储,但在访问量大的时候会导致老生代中饭呢的存活对象剧增,不仅造成清理/整理过程费时,还会造成内存紧张,甚至溢出。

js垃圾回收也有另一种方法——引用计数法:可参考引用计数法和标记清除法

更多资料可以参考
并行标记
————————————————
版权声明:本文为CSDN博主「真的137」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_38601104/article/details/88417577

原文地址:https://www.cnblogs.com/chargeworld/p/12237039.html

时间: 2024-10-21 14:15:03

内存回收机制的相关文章

(转)PHP zval内存回收机制和refcount_gc和is_ref_gc

出处 : http://blog.sina.com.cn/s/blog_75a2f94f0101gygh.html 对于PHP这种需要同时处理多个请求的程序来说,申请和释放内存的时候应该慎之又慎,一不小心便会酿成大错.另一方面,除了要安全的申请和释放内存外,还应该做到内存的最小化使用,因为它可能要处理每秒钟数以千计的请求,为了提高系统整体的性能,每一次操作都应该只使用最少的内存,对于不必要的相同数据的复制则应该能免则免.我们来看下面这段PHP代码: $a = "hello"; $b =

关于仿照java的内存回收机制实现C++的自动内存回收的一点想法

java的内存回收机制是很高效的,对软件产生的额外影响很小.而在C++中的大多数智能指针都是采用的引用计数的策略实现,当计数到0时,将所指向的指针删除.这种智能指针当应用到比较大的对象或者动态内存分配的次数非常少时.对软件的性能不会有多大的影响,反而提高了对内存的使用效率.可是一旦使用动态内存分配的次数非常巨大的时候.不仅对内存的使用效率下降,软件的运行效率也会下降很多.这主要是因为,动态分配造成的存储碎片化使可用内存减少,cache命中率也会下降.对软件性能可能会造成几百倍的损失. 目前的想法

Android 操作系统的内存回收机制(转载)

http://www.ibm.com/developerworks/cn/opensource/os-cn-android-mmry-rcycl/index.html Android APP 的运行环境 Android 是一款基于 Linux 内核,面向移动终端的操作系统.为适应其作为移动平台操作系统的特殊需要,谷歌对其做了特别的设计与优化, 使得其进程调度与资源管理与其他平台的 Linux 有明显的区别.主要包含下面几个层次: Application FrameworkApplication

Android 操作系统的内存回收机制

转自:http://android.jobbole.com/25169/ 简介:Android 是一款基于 Linux 内核,面向移动终端的操作系统.为适应其作为移动平台操作系统的特殊需要,谷歌对其做了特别的设计与优化,使应用程序关闭但不退出,并由操作系统进行进程的回收管理.本文在 Application Framework 与 Linux 内核两个层次上,以进程为粒度,对 Android 操作系统的进程资源回收机制进行了剖析.读者可以从本文获得对 Android 应用程序的生存周期的进一步理解

Android 操作系统的内存回收机制[转]

转自:http://www.ibm.com/developerworks/cn/opensource/os-cn-android-mmry-rcycl/ Android APP 的运行环境 Android 是一款基于 Linux 内核,面向移动终端的操作系统.为适应其作为移动平台操作系统的特殊需要,谷歌对其做了特别的设计与优化,使得其进程调度与资源管理与其他平台的 Linux 有明显的区别.主要包含下面几个层次: Application Framework Application Framewo

【转】Android 内存回收机制(默认回收与kernel回收)

Android APP 的运行环境 Android 是一款基于 Linux 内核,面向移动终端的操作系统.为适应其作为移动平台操作系统的特殊需要,谷歌对其做了特别的设计与优化,使得其进程调度与资源管理与其他平台的 Linux 有明显的区别.主要包含下面几个层次: Application Framework Application Framework 将整个操作系统分隔成两个部分.对应用开发者而言,所有 APP 都是运行在 Application Framework 之上,而并不需要关心系统底层的

memcache的内存回收机制

memcache不会释放内存,而是重新利用. 在缓存的清除方面,memcache是不释放已分配内存.当已分配的内存所在的记录失效后,这段以往的内存空间,memcache只会重复利用. memcached的内存回收机制不是说你设置的key到了生命周期就自动从内存中清除的,这个时候必须有一个新的对象入驻请求这个大小的chunk或者 这个过期的对象被get的时候才会清除. 那当所有给memcache的内存都被占用了,这个时候,memcache有两个设置,要么报错,要么,就是用 LRU方法,把last

php内存回收机制的学习

今天朋友去面试,回来问了一下怎么样,结果他说一脸懵逼,看来我们平时还是学习的太少了啊.于是比较好奇,果断问了一下都有哪些问题,朋友说第一个问题就是"描述PHP的垃圾回收机制",我当时听了也是一脸茫然,因为平时我们业务逻辑写的太多,很少去关注这些,但是没办法,既然有人问这个问题,看来还是很有必要了解一下的.于是马上搜了一下,网上资料文章很多,看了几篇后加上自己的一些理解记录一下. 首先看了一下官方手册,只有php5.3版本以后的才有了所谓的新的垃圾回收机制GC,那么以前是怎么干的呢?以前

js内存回收机制

Javascript语言有自己的一套内存回收机制,一般情况下局部变量和对象使用完就会被系统自动回收,无需我们理会.但是碰到闭包的情况这些变量和对象是不会被回收的,对于普通的web站点,页面刷新或跳转这些内存也会被回收.如果是单页web站点,页面切换及数据请求都是通过ajax无刷新机制实现的,页面资源无法自动回收,时间长了会严重影响性能,造成内存泄漏甚至页面崩溃直接退出,这时候手动释放不用资源就非常必要了,包含删除dom.释放对象等想手动释放含有闭包的对象时,必须先将引用对象属性的事件删除,然后设

linux kernel内存回收机制

转:http://www.wowotech.net/linux_kenrel/233.html linux kernel内存回收机制 作者:itrocker 发布于:2015-11-12 20:37 分类:内存管理 无论计算机上有多少内存都是不够的,因而linux kernel需要回收一些很少使用的内存页面来保证系统持续有内存使用.页面回收的方式有页回写.页交换和页丢弃三种方式:如果一个很少使用的页的后备存储器是一个块设备(例如文件映射),则可以将内存直接同步到块设备,腾出的页面可以被重用:如果