精华内容
下载资源
问答
  • 什么是内存泄漏

    2019-09-27 22:49:53
    本文由ImportNew-范琦琦翻译自Programcreek。欢迎加入翻译小组。转载请见文末要求。 Java最显著的优势之一就是它的内存...本教程说明了什么是内存泄漏,为什么会发生,以及如何防止它们。 1.什么是内存泄漏? 内...

    本文由 ImportNew - 范琦琦 翻译自 Programcreek。欢迎加入翻译小组。转载请见文末要求。

    Java最显著的优势之一就是它的内存管理机制。你只需简单创建对象,然后Java垃圾回收机制便会小心的分配和释放内存。然而,事实并非如此简单,因为在Java应用程序中经常发生内存泄漏。

    本教程说明了什么是内存泄漏,为什么会发生,以及如何防止它们。

    1.什么是内存泄漏?

    内存泄漏的定义: 对象不再被应用程序使用,但是垃圾回收器却不能移除它们,因为它们正在被引用。

    要理解这个定义,我们需要理解对象在内存中的状态,下图说明了哪些是未被使用的以及哪些是未被引用的。


    从图中可以看到被引用的对象和未被引用的对象。未被引用的对象将会被垃圾回收器回收,而被引用对象则不会被回收。未被引用的对象理所当然是未被使用的,因为没有其他的对象引用它。然而,未被使用的对象并不一定是未被引用的,其中一些是被引用的。这就是内存泄漏的起因。

    2.为什么会发生内存泄漏?

    让我们来看看下面这个例子,看看为什么内存泄漏会发生。在如下例子中,对象A引用了对象B。A的生命周期(t1—t4)要比B的生命周期(t2—t3)长很多。当B不再用于应用中时,A仍然持有对它的引用。在这种方式下,垃圾回收器就不能将B从内存中移除。这将可能导致出现内存不足的问题,因为如果A对更多的对象做同样的事情,那么内存中将会有很多无法被回收的对象,这将极度耗费内存空间。

    也有可能B持有大量对其他对象的引用,这些被B引用的对象也不能够被回收。所有这些未被使用的对象将会耗费宝贵的内存空间。


    3.如何阻止内存泄漏?

    以下是一些阻止内存泄漏的快速动手技巧。

    (1)注意集合类,例如HashMap,ArrayList,等等。因为它们是内存泄漏经常发生的地方。当它们被声明为静态时,它们的生命周期就同应用程序的生命周期一般长。

    (2)注意事件监听器和回调,如果一个监听器已经注册,但是当这个类不再被使用时却未被注销,就会发生内存泄漏。

    (3)“如果一个类管理它自己的内存,程序员应该对内存泄漏保持警惕。”[1] 很多时候当一个对象的成员变量指向其他对象时,不再使用时需要被置为null。

    4.一个小测验:为什么在JDK6中substring()方法会引起内存泄漏?

    为了回答这个问题,您可能需要阅读JDK6和7中的substring()

    参考文献:
    [1]Bloch,Joshua.Effective Java.Addison-Wesley Professional, 2008
    [2]IBM Developer Work.http://www.ibm.com/developerworks/library/j-leaks/

    原文链接: Programcreek 翻译: ImportNew.com 范琦琦
    译文链接: http://www.importnew.com/8715.html
    转载请保留原文出处、译者和译文链接。]

    关于作者: 范琦琦

    转载于:https://www.cnblogs.com/FANKIKI/p/8457543.html

    展开全文
  • 什么是内存泄漏

    2014-01-17 23:16:58
    ...   Java最显著的优势之一就是它的内存管理机制。你只需简单创建对象,然后Java...本教程说明了什么是内存泄漏,为什么会发生,以及如何防止它们。 1.什么是内存泄漏? 内存泄漏的定义: 对象不再被应用程序使用...

    转自:http://www.importnew.com/8715.html

     

    Java最显著的优势之一就是它的内存管理机制。你只需简单创建对象,然后Java垃圾回收机制便会小心的分配和释放内存。然而,事实并非如此简单,因为在Java应用程序中经常发生内存泄漏。

    本教程说明了什么是内存泄漏,为什么会发生,以及如何防止它们。

    1.什么是内存泄漏?

    内存泄漏的定义: 对象不再被应用程序使用,但是垃圾回收器却不能移除它们,因为它们正在被引用。

    要理解这个定义,我们需要理解对象在内存中的状态,下图说明了哪些是未被使用的以及哪些是未被引用的。

    从图中可以看到被引用的对象和未被引用的对象。未被引用的对象将会被垃圾回收器回收,而被引用对象则不会被回收。未被引用的对象理所当然是未被使用的,因为没有其他的对象引用它。然而,未被使用的对象并不一定是未被引用的,其中一些是被引用的。这就是内存泄漏的起因。

    2.为什么会发生内存泄漏?

    让我们来看看下面这个例子,看看为什么内存泄漏会发生。在如下例子中,对象A引用了对象B。A的生命周期(t1—t4)要比B的生命周期(t2— t3)长很多。当B不再用于应用中时,A仍然持有对它的引用。在这种方式下,垃圾回收器就不能将B从内存中移除。这将可能导致出现内存不足的问题,因为如 果A对更多的对象做同样的事情,那么内存中将会有很多无法被回收的对象,这将极度耗费内存空间。

    也有可能B持有大量对其他对象的引用,这些被B引用的对象也不能够被回收。所有这些未被使用的对象将会耗费宝贵的内存空间。

    3.如何阻止内存泄漏?

    以下是一些阻止内存泄漏的快速动手技巧。

    (1)注意集合类,例如HashMap,ArrayList,等等。因为它们是内存泄漏经常发生的地方。当它们被声明为静态时,它们的生命周期就同应用程序的生命周期一般长。

    (2)注意事件监听器和回调,如果一个监听器已经注册,但是当这个类不再被使用时却未被注销,就会发生内存泄漏。

    (3)“如果一个类管理它自己的内存,程序员应该对内存泄漏保持警惕。”[1] 很多时候当一个对象的成员变量指向其他对象时,不再使用时需要被置为null。

    4.一个小测验:为什么在JDK6中substring()方法会引起内存泄漏?

    为了回答这个问题,您可能需要阅读JDK6和7中的substring()

    展开全文
  • 什么是内存泄漏

    2021-02-26 10:46:35
    前言 看到一个问题: addEventListener在removeListener会不会造成内存泄漏? 理解addEventListener事件监听和 removeListener移除事件监听,想一想如何更好的回答这个问题, 那么从最基础的深入...什么是内存泄漏

    前言

    看到一个问题:

    addEventListener在removeListener会不会造成内存泄漏?

    理解addEventListener事件监听和 removeListener移除事件监听,想一想如何更好的回答这个问题, 那么从最基础的深入去学习理解一遍之后再做解答。继上一篇文章, 针对这道每日一天问题,学习了事件、事件流,事件冒泡、事件捕获。
    今题来剥析内存泄漏的概念, 以及Javascript中常见的内存泄漏源。

    思考理解

    • 内存泄漏概念
    • JS代码中常见的几个内存泄漏源

    什么是内存泄漏?

    概念:

    内存泄漏指由于疏忽或错误造成程序未能释放已经不再使用的内存的情况。内存泄漏并非指内存在物理上的消失,而是应用程序分配某段内存后,由于设计错误,失去了对该段内存的控制,因而造成了内存的浪费。

    JavaScript是一个有垃圾回收机制的语言,我们不需要手动回收内存。当本应该在垃圾回收周期中清理的内存中的对象,通过另一个对象的无意引用从根保持可以访问状态时,就会发生内存泄漏,并可能导致性能下降的后果。

    JS代码中常见的几个内存泄漏源

    全局变量

    全局变量总是从根可用,并且永远不会回收垃圾。在非严格模式下,一些错误会导致变量从本地域泄漏到全局域:

    • 将值分配给未声明的变量;
    • 使用“this”指向全局对象。
    function createGlobalVariables() {
        leaking1 = 'I leak into the global scope'; // assigning value to the undeclared variable
        this.leaking2 = 'I also leak into the global scope'; // 'this' points to the global object
    };
    createGlobalVariables();
    window.leaking1; // 'I leak into the global scope'
    window.leaking2; // 'I also leak into the global scope'
    
    

    预防措施:使用严格模式(“use strict”)。

    闭包

    函数作用域内的变量将在函数推出调用栈后清楚,并且如果函数外部没有其他指向它们的引用,则将清理它们。但闭包将保留引用的变量并保持活动状态。

    function outer(){
        const potentiallyHugeArray = [];
        return function inner(){
            // 闭包
            potentiallyHugeArray.push('hello'); //function inner is closed over the potentiallyHugeArray variable
        };
    };
    
     const sayHello = outer(); //contains definition of the function inner
    function repeat(fn, num){
        for(let i=0; i< num; i++){
            fn();
        }
    }
    repeat(sayHello,10);// each sayHello call pushes another 'Hello' to the potentiallyHugeArray
    
    // now imagine repeat(sayHello, 100000)
    
    

    在上例子中, 从任何一个函数都不会返回 potentialHugeArray,并且无法到达它,但它的大小可以无限增加,具体取决于我们调用函数 inner()的次数。

    预防措施: 闭包是肯定会用到的,所以重要的是:

    • 了解何时创建了闭包,以及它保留了哪些对象;
    • 了解闭包的预期寿命和用法(尤其是用作回调时)。

    计时器

    如果我们在代码中设置了递归计时器(recurring timer),则只要回调可调用,计时器回调中对该对象的引用就将保持活动状态。

    在下面的示例中,由于我们没有对 setInterval 的引用,因此它永远不会被清除,并且 data.hugeString 会一直保留在内存中。

    function setCallback(){
        const data = {
            counter: 0,
            hugeString: new Array(100000).join('x')
        };
        return function cb(){
            data.counter++; //data object is now part of the callback's scope
            console.log(data.counter)
        }
    }
    setIntervel(setCallback(),1000); // how do we stop it?
    

    预防措施: 尤其是在回调的生命周期不确定或undefined的情况下:

    • 了解从计时器的回调中引用了哪些对象;
    • 使用计时器返回的句柄在必要时取消它。
    function setCallbakc(){
        //unpacking the data object
        let counter = 0;
        const hugeString = new Array(100000).jion('x'); // gets removed when the setCallback returns
        return function cb() {
            counter++: // only counter is part of the callback's scope
            console.log(counter);
        }
    }
    const timerId = setIntervel(setCallback(),1000);// saving the interval ID
    // doing something
    
    clearIntervel(timerId); //stopping the timer i.e if button pressed
    

    事件侦听器

    添加后,事件侦听器将一直保持有效,直到:

    • 使用 removeEventListener()显示删除它。
    • 关联的DOM元素被移除

    对于某些类型的事件,应该是一直保留到用户离开页面为止。但是,有时我们希望事件侦听器执行特定的次数。

    const  hugeString .= new Array(100000).join('x');
    document.addEventListener('keyup',function(){// anonymous inline function - can't remove it
        doSomething(hugeString); //hugeString is now forever kept in the callback's scope
    });
    

    在上面的示例中,用一个匿名内联函数作为事件侦听器,这意味着无法使用 removeEventListener() 将其删除。同样,该文档也无法删除,因此即使我们只需要触发它一次,它和它域中的内容就都删不掉了。

    预防措施: 我们应该始终创建指向事件侦听器的引用并将其传递给 removeEventListener(),来注销不再需要的事件侦听器。

    function listener(){
        doSomething(hugeString);
    }
    document.addEventListener('keyup',listener); //named function can be referenced here...
    document.removeEventlistener('keyup',listener); //  ...and here
    
    
    如果事件侦听器仅执行一次,则addEventListener()可以使用第三个参数。假设{once: true} 作为第三个参数传递给 addEventListener(),则在处理一次事件后, 将自动删除侦听器函数。
    document.addEventListener('keyup', function listener() {
        doSomething(hugeString);
    }, {once: true}); // listener will be removed after running once
    

    缓存

    如果我们不删除未使用的对象且不控制对象大小,那么缓存就会失控。

    let user_1 = { name: "Peter", id: 12345 };
    let user_2 = { name: "Mark", id: 54321 };
    const mapCache = new Map();
    function cache(obj){
        if (!mapCache.has(obj)){
            const value = `${obj.name} has an id of ${obj.id}`;
            mapCache.set(obj, value);
            return [value, 'computed'];
        }
        return [mapCache.get(obj), 'cached'];
    }
    cache(user_1); // ['Peter has an id of 12345', 'computed']
    cache(user_1); // ['Peter has an id of 12345', 'cached']
    cache(user_2); // ['Mark has an id of 54321', 'computed']
    console.log(mapCache); // ((…) => "Peter has an id of 12345", (…) => "Mark has an id of 54321")
    user_1 = null; // removing the inactive user
    // Garbage Collector
    console.log(mapCache); // ((…) => "Peter has an id of 12345", (…) => "Mark has an id of 54321") // first entry is still in cache
    

    在上面的示例中,缓存仍保留在 user_1 对象上。因此,我们还需要清除不会再重用的条目的缓存。

    可能的解决方案:我们可以使用 WeakMap。它的数据结构中,键名是对象的弱引用,它仅接受对象作为键名,所以其对应的对象可能会被自动回收。当对象被回收后,WeakMap 自动移除对应的键值对。在以下示例中,在使 user_1 对象为空后,下一次垃圾回收后关联的条目会自动从 WeakMap 中删除。

    let user_1 = { name: "Peter", id: 12345 };
    let user_2 = { name: "Mark", id: 54321 };
    const weakMapCache = new WeakMap();
    function cache(obj){
        // ...same as above, but with weakMapCache
        return [weakMapCache.get(obj), 'cached'];
    }
    cache(user_1); // ['Peter has an id of 12345', 'computed']
    cache(user_2); // ['Mark has an id of 54321', 'computed']
    console.log(weakMapCache); // ((…) => "Peter has an id of 12345", (…) => "Mark has an id of 54321"}
    user_1 = null; // removing the inactive user
    // Garbage Collector
    console.log(weakMapCache); // ((…) => "Mark has an id of 54321") - first entry gets garbage collected
    

    分离的DOM元素

    如果 DOM 节点具有来自 JavaScript 的直接引用,则即使从 DOM 树中删除了该节点,也不会对其垃圾回收。

    在以下示例中,我们创建了一个 div 元素并将其附加到 document.body。removeChild() 无法正常工作,并且由于仍然存在指向 div 的变量,所以堆快照将显示分离的 HTMLDivElement。

    function createElement() {
        const div = document.createElement('div');
        div.id = 'detached';
        return div;
    }
    // this will keep referencing the DOM element even after deleteElement() is called
    const detachedDiv = createElement();
    document.body.appendChild(detachedDiv);
    function deleteElement() {
        document.body.removeChild(document.getElementById('detached'));
    }
    deleteElement(); // Heap snapshot will show detached div#detached
    
    

    怎么预防呢?一种方案是将 DOM 引用移入本地域。在下面的示例中,在函数 appendElement() 完成之后,将删除指向 DOM 元素的变量。

    function createElement() {...} // same as above
    // DOM references are inside the function scope
    function appendElement() {
        const detachedDiv = createElement();
        document.body.appendChild(detachedDiv);
    }
    appendElement();
    function deleteElement() {
         document.body.removeChild(document.getElementById('detached'));
    }
    deleteElement(); // no detached div#detached elements in the Heap Snapshot
    

    参考:

    https://www.ditdot.hr/en/causes-of-memory-leaks-in-javascript-and-how-to-avoid-them

    展开全文
  • 什么是内存泄漏?有什么危害

    千次阅读 2019-04-18 11:31:56
    1、什么是内存泄漏 内存泄漏是指你向系统申请分配内存进行使用(new/malloc),然后系统在堆内存中给这个对象申请一块内存空间,但当我们使用完了却没有归系统(delete),导致这个不使用的对象一直占据内存单元,...

    1、什么是内存泄漏

        内存泄漏是指你向系统申请分配内存进行使用(new/malloc),然后系统在堆内存中给这个对象申请一块内存空间,但当我们使用完了却没有归系统(delete),导致这个不使用的对象一直占据内存单元,造成系统将不能再把它分配给需要的程序。

        一次内存泄漏的危害可以忽略不计,但是内存泄漏堆积则后果很严重,无论多少内存,迟早会被占完,造成内存泄漏。

    2、引起内存泄漏的原因

    1、分配给程序的内存忘记回收;

        这个是不应该发生的事情,但也是代码中常见的问题。分配的内存用完之后,就一定要回收,避免造成内存泄漏。

    2、程序代码有问题,造成系统没有办法回收;

        Temp1 = new BYTE[100];
        Temp2 = new BYTE[100];
        Temp2 = Temp1;

        这样,Temp2的内存地址就丢掉了,而且永远都找不回了,这个时候Temp2的内存空间想回收都 没有办法。

    3、某些API函数操作不正确,造成内存泄漏;

    3、内存泄漏的危害

          1、频繁GC:系统分配给每个应用的内存资源都是有限的,内存泄漏导致其他组件可用的内存变少后,一方面会使得GC的频率加剧,再发生GC的时候,所有进程都必须等待,GC的频率越高,用户越容易感应到卡顿。另一方面内存变少,可能使得系统额外分配给该对象一些内存,而影响整个系统的运行情况。

        2、导致程序运行崩溃:一旦内存不足以为某些对象分配所需要的空间,将会导致程序崩溃,造成体验差。

    4、Java的垃圾回收机制GC

    原文地址:https://blog.csdn.net/zy_jibai/article/details/80957169

         1、CG的作用:释放掉不可到达的对象的内存。

         2、不可达是个什么概念?

        首先我们要搞清楚Java的内存分区了,其中有两个非常重要的就是栈内存和堆内存

    • 堆内存存放创建的对象的内存
    • 栈内存存放指向对象的引用和普通数据类型

    例如创建一个变量:String str1 = new String("test");

    由此可以说明Java操作对象全部都是匿名操作。在创建之初,每一个堆内存中对象的内存,在栈中都会有一个值(引用)指向他,而有一部分值在我们使用完毕后会将引用置空,这就会有一些堆中的内存没有引用指向,又因为Java中对对象是匿名操作,所以对这些没有栈中内存存储的引用指向的对象称之为不可触及的对象。

    工作原理

    简单介绍一下GC的工作原理:

    首先GC会扫描栈内存中的引用,然后会遍历堆内存中的引用,这样就会查找出内存中不可触及的对象,然后将其释放掉。

    说到这里大家应该发现一个问题,GC回收的只是堆中的内存,而没有栈中的内存,这是因为栈中已分配的内存会随着哟个方法结束的时候释放掉,所以不用担心栈内存中会存在内存泄漏的问题。

    PS:定义变量的时候,慎用static,例如静态的集合中的数据都不会被回收

     

     

    展开全文
  • 1、什么是内存泄漏 内存泄漏是指你向系统申请分配内存进行使用(new/malloc),然后系统在堆内存中给这个对象申请一块内存空间,但当我们使用完了却没有归系统(delete),导致这个不使用的对象一直占据内存单元,...
  • 什么是内存泄漏?如何检测程序中是否存在内存泄漏?预防方式? 什么是内存泄漏? a.堆内存泄漏(Heap leak) 堆内存指的是程序执行中依据须要分配通过malloc / calloc / realloc / new等从堆中分配的一块内存,用完后...
  • 1、什么是内存泄漏(memory leak)? 应用程序中已动态分配的堆内存由于某种原因(比如没有任何指针指向申请的内存)导致程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果。...
  • 什么是内存泄漏,如何避免 内存泄漏:可以这么解释——程序刚跑起来,运行很OK。跑了几个小时,或者跑几天程序就崩溃了。 代码为解释如下: while(1){ sleep(1); int *p =malloc(1024); /*1、每一秒申请1M的空间。 2...
  • 一、什么是内存泄漏 通俗讲就是该回收的对象,因为引用问题没有被回收,最终会产生OOM 二、产生的原因 一个长声明周期的对象持有一个短生命周期对象的引用 三、Java如何解决 Java不会解决,需要开发者通过...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 4,918
精华内容 1,967
关键字:

什么是内存泄漏