Débordement de pile JS, fuites de mémoire, petites notes sur le ramasse-miettes, le tout

débordement de pile

Qu'est-ce que le débordement de pile ? Nous savons que le stockage de données dans JS est divisé en pile et en tas. Le fonctionnement du code de programme nécessite une certaine quantité d'espace de stockage informatique. Et le retour continuera à effectuer les opérations de poussée et d'extraction de la pile (récursivité) , et les ressources occupés dans la pile changent également constamment en conséquence, mais une fois que votre appel signifie qu'il y a trop d'opérations d'empilement, et le retour signifie que le popping n'est pas suffisant. A ce moment, la pile sera pleine, et celles qui sont poussées dans la pile débordera.

Exemple avec code ;

function isEven(n) {
    if (n === 0) {
        return true;
    }
    if (n === 1) {
        return false;
    }
    return isEven(Math.abs(n) - 2);
}
//1.console.log(factorial(10))    true    运行比较快
//2.console.log(factorial(10000000))    Uncaught RangeError: Maximum call stack size exceeded
//错误是 最大调用超过堆栈大小

S'il y a trop de couches récursives, une erreur sera signalée. Pourquoi ? La raison en est que dans le processus d'exécution du code, le programme a besoin d'une certaine quantité d'espace de calcul, c'est-à-dire la pile. La taille générale est d'environ 1 Mo. , il dépassera l'espace de pile alloué par le programme et une erreur sera signalé. Alors, comment résoudre ce problème ? En prenant l'exemple récursif ci-dessus comme exemple, la solution est la suivante (nous avons mentionné les fermetures plus tôt, et nous utiliserons des fermetures pour les résoudre ici) :

function isEven (num) {
    if (num === 0) {
        return true;
    }
 
    if (num === 1) {
        return false;
    }
 
    return function() {
        return isEven(Math.abs(num) - 2);
    }
}
//Outputs: true
console.log(isEven(4)()());
//此时每次调用时,返回一个匿名函数,匿名函数执行相关的参数和局部变量将会释放,不会额外增加堆栈大小。
//个人理解,新出来一层,然后外层的就销毁了,因为最外层的isEven已经销毁了

fuite de mémoire

Qu'est-ce qu'une fuite de mémoire ? Une fuite de mémoire signifie qu'il y a un morceau de mémoire dans la pile allouée par le programme qui ne peut être ni utilisé ni récupéré. (Ici, vous pouvez contacter les points de connaissance de la référence forte et de la référence faible, la différence entre la carte et l'objet)

Situations qui conduisent à des fuites de mémoire :

//1.*********************************************
//【函数内未使用声明变量关键字的变量[意外的全局变量]】
//全局变量的生命周期最长,直到页面关闭前,它都存活着,所以全局变量上的内存一直都不会被回收。
function func() {
    a = 1;
}
//2.*********************************************
//【未销毁的定时器,要记得clearTimeout()】
//setTimeout 和 setInterval 是由浏览器专门线程来维护它的生命周期。
//所以当在某个页面使用了定时器,当该页面销毁时,没有手动去释放清理这些定时器的话,那么这些定时器还是存活着的。
setInterval(function () {
    console.log(1)
}, 1000);
//3.*********************************************
//【DOM以外的节点引用】
//DOM 元素的生命周期正常是取决于是否挂载在 DOM 树上,当从 DOM 树上移除时,也就可以被销毁回收了
//但如果某个 DOM 元素,在 js 中也持有它的引用时,那么它的生命周期就由 js 和是否在 DOM 树上两者决定了
//记得移除时,两个地方都需要去清理才能正常回收它。
var elements = {
    button: document.getElementById('button'),
};
function doStuff() {
    button.click();
}
function removeButton() {
    document.body.removeChild(document.getElementById('button')); 
    // 这时,我们仍然有一个引用指向全局中的elements。button这个节点仍在内存中,不会被回收。
}
//4.*********************************************
//【闭包的循环引用】
function my(name) {
    function sayName() {
        console.log(name)
    }
    return sayName
}
//在函数my()内部创建的sayName()函数是不会被回收机制回收
//如果闭包不被调用,由于闭包会携带包含它的函数的作用域,因此会比其他函数占用更多的内存。过度使用闭包可能会导致内存占用过多。
var sayHi= my("tom")
sayHi() //tom
//5.*********************************************
//【网络回调】
//某些场景中,在某个页面发起网络请求,并注册一个回调,且回调函数内持有该页面某些内容。
//那么,当该页面销毁时,应该注销网络的回调,否则,因为网络持有页面部分内容,也会导致页面部分内容无法被回收。

collecte des ordures

  • Mécanisme de collecte des ordures, il existe généralement deux types de nettoyage des langues orphelines, l'un est le nettoyage automatique, l'autre est le nettoyage manuel (GC), et js n'a qu'un nettoyage automatique

  • Le mécanisme de récupération de place consiste à définir l'objet qui référence l'adresse dans la paire sur null, et de définir tous les objets qui référencent l'adresse sur null, et de supprimer l'écouteur d'événement

  • Il ne sera pas effacé immédiatement et le ramasse-miettes l'effacera à un moment approprié en fonction de la situation de la mémoire. La mémoire objet dans le tas ne sera pas recyclée tant qu'elle n'aura pas atteint un certain niveau

    var obj={
            a:1,
            b:2
        };
    var obj1=obj;
    obj=null;
    obj1=null;
        // 必须将所有引用的对象全部设为null 堆里面才会变成孤儿,要不然无法回收

bon article à ce sujet

un autre article

Guess you like

Origin blog.csdn.net/qq_42533666/article/details/129108292