精华内容
下载资源
问答
  • 本篇我们就来分析其中一种造成OOM的场景,它就是罪恶的内存泄漏。对于这样的称呼,我们并不陌生,甚至屡次与之"并肩作战",只不过它就是一个猪队友,只会不断送塔.......本篇分为3部分:1.Han...

    在android开发过程中,我们可能会遇到过令人奔溃的OOM异常,面对这样的异常我们是既熟悉又深恶痛绝的,因为造成OOM的原因有很多种情况,如加载图片过大,某已不再使用的类未被GC及时回收等等......本篇我们就来分析其中一种造成OOM的场景,它就是罪恶的内存泄漏。对于这样的称呼,我们并不陌生,甚至屡次与之"并肩作战",只不过它就是一个猪队友,只会不断送塔.......

    本篇分为3部分:

    1.Handler内存泄漏例子说明以及原理阐明

    2.问题验证(如果感觉繁琐请直接跳过)

    3.Handler内存泄漏解决方法

    1.Handler内存泄漏例子说明以及原理阐明

    Handler,我们已经相当熟悉了,而且经常用得不亦乐乎,但就是因为太熟悉了,才会偶尔被它反捅一刀,血流不止......还记得我们曾经满怀信心地使用着如下的优美而又简洁的代码不?

    467cfdaaaeb2c841c6eeac49e29006f1.png

    不怕你吓着,实话告诉你,这个代码已经造成内存泄漏了!!!不相信?我们使用Android lint工具检测一下该类的代码:

    a3571e0ad65099171b9a885b76f02950.png

    面对现实吧,那为什么会这样呢?在java中非静态内部类和匿名内部类都会隐式持有当前类的外部引用,由于Handler是非静态内部类所以其持有当前Activity的隐式引用,如果Handler没有被释放,其所持有的外部引用也就是Activity也不可能被释放,当一个对象一句不需要再使用了,本来该被回收时,而有另外一个正在使用的对象持有它的引用从而导致它不能被回收,这导致本该被回收的对象不能被回收而停留在堆内存中,这就产生了内存泄漏(上面的例子就是这个原因)。最终也就造成了OOM.......我们再来段清晰的代码,我们来使用mHandler发送一个延迟消息:

    259ef3ed1081f715e7291d931996551f.png

    分析:当我们执行了HandlerActivity的界面时,被延迟的消息会在被处理之前存在于主线程消息队列中5分钟,而这个消息中又包含了Handler的引用,而我们创建的Handler又是一个匿名内部类的实例,其持有外部HandlerActivity的引用,这将导致了HandlerActivity无法回收,进行导致HandlerActivity持有的很多资源都无法回收,从而就造成了传说中的内存泄露问题!

    2.问题验证(如果感觉繁琐请直接跳过)

    为了进一步验证内存泄漏问题,我们在该类中创建一个int数组,该数组分配的内存大小为2m,然后我们用DDMS来查看heap内存,然后使用GC回收,看看内存会不会有变化:

    dbff25216c34859a4827a02387484e40.png

    第一次启动app时,head内存为12.5M,已经分配内容(Allocated):8.5M,空闲内存:4M,我们频繁点击GC按钮,内存并没有发生明显变化,现在我们点击手机返回健,推出应用,然后再重新进入,同样检测一下head内存:

    4b1c2109250d4f6d5c9fd620585fa054.png

    我们发现head内存:20.5M,Allocated:16.5M,Free:4M,堆内存和已经分配内存近乎翻倍,我们继续频繁点击GC, 看看能否被回收?结果内存并没有明显变化,现在我们继续点击手机返回健,推出应用,然后再重新进入,同样再次检测一下head内存:

    b5259c6f2408a88e7a0eccd64b34afca.png

    我们发现head内存:28.5M,Allocated:24.5M,Free:4M,堆内存和已经分配内存又增加了,而且无论我们如何点击GC回收内存,内存都没有明显变化,而且每启动一次该页面,内存就增加一倍!这也就说存在在某个类只创建而没销毁的情况,其实就是存在内存泄漏问题。我们使用MAT工具进一步验证这个问题,我们来看一组Histogram的数据和dominator tree数据,首先是Histogram的数据:

    677320dd454901254de2c378ac189e2c.png

    dominator tree数据:

    918fbf7d4cbfc4e99b1436e395861079.png

    同时存在三个一样的HandlerActivity和内部类,这就足以说明HandlerActvity只有创建没被销毁了吧,也就是说Handler造成的内存泄漏真的存在。

    3.Handler内存泄漏解决方法

    解决这个问题思路就是使用静态内部类并继承Handler时(或者也可以单独存放成一个类文件)。因为静态的内部类不会持有外部类的引用,所以不会导致外部类实例的内存泄露。当你需要在静态内部类中调用外部的Activity时,我们可以使用弱引用来处理。另外关于同样也需要将Runnable设置为静态的成员属性。修改后不会导致内存泄露的代码如下:

    package com.zejian.handlerlooper;

    import android.app.Activity;

    import android.os.Bundle;

    import android.os.Handler;

    import android.os.Message;

    import java.lang.ref.WeakReference;

    /**

    * Created by zejian on 16/3/6.

    */

    public class HandlerActivity extends Activity {

    //创建一个2M大小的int数组

    int[] datas=new int[1024*1024*2];

    // Handler mHandler = new Handler(){

    // @Override

    // public void handleMessage(Message msg) {

    // super.handleMessage(msg);

    // }

    // };

    /**

    * 创建静态内部类

    */

    private static class MyHandler extends Handler{

    //持有弱引用HandlerActivity,GC回收时会被回收掉.

    private final WeakReference mActivty;

    public MyHandler(HandlerActivity activity){

    mActivty =new WeakReference(activity);

    }

    @Override

    public void handleMessage(Message msg) {

    HandlerActivity activity=mActivty.get();

    super.handleMessage(msg);

    if(activity!=null){

    //执行业务逻辑

    }

    }

    }

    private static final Runnable myRunnable = new Runnable() {

    @Override

    public void run() {

    //执行我们的业务逻辑

    }

    };

    @Override

    protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);

    setContentView(R.layout.activity_handler_leak);

    MyHandler myHandler=new MyHandler(this);

    //解决了内存泄漏,延迟5分钟后发送

    myHandler.postDelayed(myRunnable, 1000 * 60 * 5);

    }

    }

    Handler的内存泄漏问题到此分析解决完成。其实产生内存泄漏的还有好几种情况,比如多线程造成的内存泄漏,静态变量造成的内存泄漏,单例模式造成的内存泄漏等等.......当然这些不在本篇的范围内,就不过多分析啦。

    以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

    展开全文
  • 2、setTimeout 的第一个参数使用字符串而非函数的话,会引发内存泄漏 3、闭包、控制台日志、循环(在两个对象彼此引用且彼此保留时,就会产生一个循环) Js内存泄露解决方法 1.global variables:对未声明的变量的...

    1、垃圾回收器定期扫描对象,并计算引用了每个对象的其他对象的数量。如果一个对象的 引用数量为 0(没有其他对象引用过该对象),或对该对象的惟一引用是循环的,那么该对象的 内存即可回收

    2、setTimeout 的第一个参数使用字符串而非函数的话,会引发内存泄漏

    3、闭包、控制台日志、循环(在两个对象彼此引用且彼此保留时,就会产生一个循环)

    Js内存泄露解决方法

    1.global variables:对未声明的变量的引用在全局对象内创建一个新变量。在浏览器中,全 局对象就是 window。

    function foo(arg) {
    bar = 'some text'; // 等同于 window.bar = 'some text';

    }

    解决: 创建意外的全局变量

    function foo() {
    this.var1 = 'potential accident'

    }

    2.可以在 JavaScript 文件开头添加 “use strict”,使用严格模式。这样在严格模式 下解析 JavaScript 可以防止意外的全局变量

    3.在使用完之后,对其赋值为 null 或者重新分配

    4.被忘记的 Timers 或者 callbacks

    在 JavaScript 中使用 setInterval 非常常见 大多数库都会提供观察者或者其它工具来处理回调函数,在他们自己的实例变为不可达时,

    会让回调函数也变为不可达的。对于 setInterval,下面这样的代码是非常常见的:

    var serverData = loadData();
    setInterval(function() {
    var renderer = document.getElementById('renderer'); if(renderer) {
    renderer.innerHTML = JSON.stringify(serverData);
    }

    }, 5000); //This will be executed every ~5 seconds

    这个例子阐述着 timers 可能发生的情况:计时器会引用不再需要的节点或数据

    5.闭包:一个可以访问外部(封闭)函数变量的内部函数

    JavaScript 开发的一个关键方面就是闭包:一个可以访问外部(封闭)函数变量的内部函数。

    由于 JavaScript 运行时的实现细节,可以通过以下方式泄漏内存:

    var theThing = null;
    var replaceThing = function () {

    var originalThing = theThing; var unused = function () {

    if (originalThing) // a reference to 'originalThing' console.log("hi");

    };
    theThing = {

    longStr: new Array(1000000).join('*'), someMethod: function () {

    console.log("message"); }

    }; };

    setInterval(replaceThing, 1000);

    DOM 引用

    有时候,在数据结构中存储 DOM 结构是有用的。假设要快速更新表中的几行内容。将每行 DOM 的引用存储在字典或数组中可能是有意义的。当这种情况发生时,就会保留同一 DOM
    用:一个在 DOM 树种,另一个在字典中。如果将来某个时候你决定要删除这些行,
    用都不可达。

    var elements = {
    button: document.getElementById('button'),

    image: document.getElementById('image')

    };

    function doStuff() {
    elements.image.src = 'http://example.com/image_name.png';

    }
    function removeImage() {

    // The image is a direct child of the body element. document.body.removeChild(document.getElementById('image')); // At this point, we still have a reference to #button in the //global elements object. In other words, the button element is //still in memory and cannot be collected by the GC.

    }

    展开全文
  • Java内存泄漏解决之道

    2021-02-12 21:53:25
    虽然GC有效地处理了大部分内存,但它并不能保证内存泄漏的万无一失的解决方案。GC很聪明,但并不完美。即使在尽职尽责的开发人员的应用程序中,内存泄漏仍然可能会泄漏。仍然可能存在应用程序生成大量多余对象的情况...

    Java的核心优势之一是在内置垃圾收集器(简称GC)的帮助下实现自动内存管理。GC隐式地负责分配和释放内存,因此能够处理大多数内存泄漏问题。

    虽然GC有效地处理了大部分内存,但它并不能保证内存泄漏的万无一失的解决方案。GC很聪明,但并不完美。即使在尽职尽责的开发人员的应用程序中,内存泄漏仍然可能会泄漏。

    仍然可能存在应用程序生成大量多余对象的情况,从而耗尽关键内存资源,有时会导致整个应用程序失败。

    内存泄漏是Java中的一个真正问题。在本教程中,我们将了解内存泄漏的潜在原因是什么,如何在运行时识别它们,以及如何在我们的应用程序中处理它们。

    什么是内存泄漏

    内存泄漏是堆中存在不再使用的对象但垃圾收集器无法从内存中删除它们的情况,因此它们会被不必要地维护。

    内存泄漏很糟糕,因为它会阻止内存资源并降低系统性能。如果不处理,应用程序最终将耗尽其资源,最终以致命的java.lang.OutOfMemoryError终止。

    堆内存中有两种不同类型的对象 - 引用和未引用。引用的对象是在应用程序中仍具有活动引用的对象,而未引用的对象没有任何活动引用。

    垃圾收集器会定期删除未引用的对象,但它永远不会收集仍在引用的对象。

    内存泄漏的症状

    应用程序长时间连续运行时性能严重下降

    应用程序中的OutOfMemoryError堆错误

    自发和奇怪的应用程序崩溃

    应用程序偶尔会耗尽数据库连接池对象

    让我们仔细看看其中一些场景以及如何处理它们。

    Java中的内存泄漏类型

    在任何应用程序中,由于多种原因都可能发生内存泄漏:

    1. 静态字段

    可能导致潜在内存泄漏的第一种情况是大量使用静态变量。

    在Java中,静态字段的生命周期通常与正在运行的应用程序的整个生命周期相匹配(除非ClassLoader符合垃圾回收的条件)。

    让我们创建一个填充静态 List的简单Java程序  :

    public class StaticTest {

    public static List list = new ArrayList<>();

    public void populateList() {

    for (int i = 0; i < 10000000; i++) {

    list.add(Math.random());

    }

    Log.info("Debug Point 2");

    }

    public static void main(String[] args) {

    Log.info("Debug Point 1");

    new StaticTest().populateList();

    Log.info("Debug Point 3");

    }

    }

    现在,如果我们在程序执行期间分析堆内存,那么我们将看到调试点1和2之间,正如预期的那样,堆内存增加了。

    但是当我们离开populateList()所在的调试点3时,堆内存还没有被垃圾收集。

    在上面的程序中,在第2行中,如果我们只删除关键字  static,这次我们离开  populateList()  方法之后,列表的所有内存都被垃圾收集,因为我们没有任何对它的引用。

    如何预防呢?

    最大限度地减少静态变量的使用

    使用单例时,依赖于延迟加载对象而不是急切加载的实现

    2. 未关闭的连接池资源

    每当我们建立新连接或打开流时,JVM都会为这些资源分配内存。一些示例包括数据库连接,输入流和会话对象。

    忘记关闭这些资源可以阻止内存,从而使它们远离GC的范围。如果异常阻止程序执行到达处理代码以关闭这些资源的语句,则甚至可能发生这种情况。

    在任何一种情况下,资源留下的开放连接都会消耗内存,如果我们不处理它们,它们可能会降低性能,甚至可能导致OutOfMemoryError。

    如何预防呢?

    始终使用finally块来关闭资源

    关闭资源的代码(甚至在  finally块中)本身不应该有任何异常

    使用Java 7+时,我们可以使用try -with-resources块

    3. 不正确的equals()和hashCode()实现

    在定义新类时,一个非常常见的疏忽是不为equals()和hashCode()方法编写适当的重写方法。

    HashSet  和  HashMap  在许多操作中使用这些方法,如果它们没有被正确覆盖,那么它们可能成为潜在的内存泄漏问题的来源。

    让我们以一个简单的Person  类为例,  并将其用作HashMap中的键  :

    public class Person {

    public String name;

    public Person(String name) {

    this.name = name;

    }

    }

    现在我们将重复的Person对象插入到使用此对象作为键的Map中。

    请记住,Map不能包含重复的键:

    @Test

    public void givenMap_whenEqualsAndHashCodeNotOverridden_thenMemoryLeak() {

    Map map = new HashMap<>();

    for(int i=0; i<100; i++) {

    map.put(new Person("jon"), 1);

    }

    Assert.assertFalse(map.size() == 1);

    }

    这里我们使用Person作为key,由于Map不允许重复键,因此我们作为键插入的众多重复Person对象不应增加内存。

    但是由于我们没有定义正确的equals()方法,重复的对象会堆积并增加内存,这就是我们在内存中看到多个对象的原因。

    如果我们正确地重写了  equals()  和hashCode()方法,那么在这个Map中只会存在一个Person对象。让我们一起来看看正确实现的equals()和hashCode()方法:

    public class Person {

    public String name;

    public Person(String name) {

    this.name = name;

    }

    @Override

    public boolean equals(Object o) {

    if (o == this) return true;

    if (!(o instanceof Person)) {

    return false;

    }

    Person person = (Person) o;

    return person.name.equals(name);

    }

    @Override

    public int hashCode() {

    int result = 17;

    result = 31 * result + name.hashCode();

    return result;

    }

    }

    在这种情况下,以下断言将成立:

    @Test

    public void givenMap_whenEqualsAndHashCodeNotOverridden_thenMemoryLeak() {

    Map map = new HashMap<>();

    for(int i=0; i<2; i++) {

    map.put(new Person("jon"), 1);

    }

    Assert.assertTrue(map.size() == 1);

    }

    另一个例子是使用像Hibernate这样的ORM工具,它使用equals()  和hashCode()方法来分析对象并将它们保存在缓存中。

    如果不覆盖这些方法,则内存泄漏的可能性非常高,因为Hibernate将无法比较对象并将使用重复对象填充其缓存。

    如何预防呢?

    根据经验,在定义新实体时,始终覆盖equals()和hashCode()方法

    它不仅仅足以覆盖,但这些方法也必须以最佳方式被覆盖

    4.引用外类的内部类

    这种情况发生在非静态内部类(匿名类)的情况下。对于初始化,这些内部类总是需要封闭类的实例。

    默认情况下,每个非静态内部类都包含对其包含类的隐式引用。如果我们在应用程序中使用这个内部类'对象,那么即使在我们的包含类'对象超出范围之后,它也不会被垃圾收集。

    因为内部类对象隐式地保存对外部类对象的引用,从而使其成为垃圾收集的无效候选者。在匿名类的情况下也是如此。

    如何预防呢?

    如果内部类不需要访问当前包含这个内部类的父类的成员时,请考虑将其转换为静态类

    5.finalize()方法

    是潜在的内存泄漏问题的另一个来源。每当重写类的  finalize()方法时,该类的对象不会立即被垃圾收集。相反,GC将它们排队等待最终确定,在稍后的时间点才会发送GC。

    如果用finalize()方法编写的代码不是最佳的,并且finalize队列无法跟上Java垃圾收集器,那么迟早,我们的应用程序注定要遇到  OutOfMemoryError。

    如何预防呢?

    我们应该总是避免使用finalize方法

    6. 内部字符串

    Java 7的重大变化:Java String池在从PermGen转移到HeapSpace了。但是对于在版本6及更低版本上运行的应用程序,在使用大型字符串时我们应该更加专心。

    如果我们读取一个庞大的大量String对象,并在该对象上调用intern(),那么它将转到字符串池,它位于PermGen(永久内存)中,并且只要我们的应用程序运行就会保留在那里。这会阻止内存收集并在我们的应用程序中造成重大内存泄漏。

    如何预防呢?

    解决此问题的最简单方法是升级到最新的Java版本,因为String池从Java版本7开始转移到HeapSpace

    如果处理大型字符串,请增加PermGen空间的大小以避免任何潜在的OutOfMemoryErrors:

    -XX:MaxPermSize=512m

    7. 使用ThreadLocal

    ThreadLocal使我们能够将状态隔离到特定线程,从而允许我们实现线程安全。

    使用此构造时,  每个线程将保留对其ThreadLocal变量副本的隐式引用,并且将保留其自己的副本,而不是跨多个线程共享资源,只要该线程处于活动状态即可。

    尽管有其优点,ThreadLocal  变量的使用仍存在争议,因为如果使用不当,它们会因引入内存泄漏而臭名昭着。Joshua Bloch  曾评论线程本地用法:

    “如果在许多地方已经注意到,使用线程池的粗糙使用与ThreadLocal的粗略使用会导致意外的对象保留。但把责任归咎于ThreadLocal是没有根据的。“

    内存泄漏与ThreadLocals

    一旦保持线程不再存在,ThreadLocals应该被垃圾收集。但是当ThreadLocals与现代应用程序服务器一起使用时,问题就出现了。

    现代应用程序服务器使用线程池来处理请求而不是创建新请求(例如  ,在Apache Tomcat的情况下为Executor)。此外,他们还使用单独的类加载器。

    由于 应用程序服务器中的线程池在线程重用的概念上工作,因此它们永远不会被垃圾收集 - 相反,它们会被重用来处理另一个请求。

    现在,如果任何类创建  ThreadLocal 变量但未显式删除它,则即使在Web应用程序停止后,该对象的副本仍将保留在工作线程中,从而防止对象被垃圾回收。

    如何预防呢?

    在不再使用ThreadLocals时清理ThreadLocals是一个很好的做法-  ThreadLocals提供了  remove()方法,该方法删除了此变量的当前线程值

    不要使用  ThreadLocal.set(null) 来清除该值  - 它实际上不会清除该值,而是查找与当前线程关联的Map并将键值对设置为当前线程并分别为null

    最好将  ThreadLocal 视为需要在finally块中关闭的资源,以  确保它始终关闭,即使在异常的情况下:

    try {

    threadLocal.set(System.nanoTime());

    //... further processing}

    finally {

    threadLocal.remove();

    }

    处理内存泄漏的其他策略

    虽然在处理内存泄漏时没有一个通用的解决方案,但有一些方法可以最大限度地减少这些泄漏。

    1. 启用分析

    Java分析器如Java VisualVM是通过应用程序监视和诊断内存泄漏的工具。他们分析我们的应用程序内部发生了什么 - 例如,如何分配内存。

    使用分析器,我们可以比较不同的方法,并找到我们可以最佳地使用我们的资源的领域。

    2. 增强垃圾收集

    通过启用详细垃圾收集,我们将跟踪GC的详细跟踪。要启用此功能,我们需要将以下内容添加到JVM配置中:

    -verbose:gc

    通过添加此参数,我们可以看到GC内部发生的详细信息。

    3. 使用引用对象避免内存泄漏

    还可以使用java中的引用对象来构建java.lang.ref包来处理内存泄漏。使用java.lang.ref包,我们使用对象的特殊引用,而不是直接引用对象,这些对象可以很容易地进行垃圾回收。

    4. Eclipse内存泄漏警告

    对于JDK 1.5及更高版本的项目,Eclipse会在遇到明显的内存泄漏情况时显示警告和错误。因此,在Eclipse中开发时,我们可以定期访问“问题”选项卡,并对内存泄漏警告(如果有)更加警惕

    5. 基准测试

    我们可以通过执行基准来测量和分析Java代码的性能。这样,我们可以比较替代方法的性能来完成相同的任务。这可以帮助我们选择更好的方法,并可以帮助我们节约记忆。

    6. 代码评审

    最后,我们总是采用经典的老式方式进行简单的代码演练。

    在某些情况下,即使是这种微不足道的方法也可以帮助消除一些常见的内存泄漏问题。

    展开全文
  • 摘要:通过介绍内存泄漏问题原理及检视方法,希望后续能够从编码检视环节就杜绝内存泄漏导致...另一方面,由于内存泄漏问题很可能导致单板运行固定时间以后就复位,只能通过批量升级才能解决,实际影响也很恶劣。同...

    摘要:通过介绍内存泄漏问题原理及检视方法,希望后续能够从编码检视环节就杜绝内存泄漏导致的网上问题发生。

    1. 前言

    最近部门不同产品接连出现内存泄漏导致的网上问题,具体表现为单板在现网运行数月以后,因为内存耗尽而导致单板复位现象。一方面,内存泄漏问题属于低级错误,此类问题遗漏到现网,影响很坏;另一方面,由于内存泄漏问题很可能导致单板运行固定时间以后就复位,只能通过批量升级才能解决,实际影响也很恶劣。同时,接连出现此类问题,尤其是其中一例问题还是我们老员工修改引入,说明我们不少员工对内存泄漏问题认识还是不够深刻的。本文通过介绍内存泄漏问题原理及检视方法,希望后续能够从编码检视环节就杜绝此类问题发生。

    说明:预防内存泄漏问题有多种方法,如加强代码检视、工具检测和内存测试等,本文聚集于开发人员能力提升方面。

    2. 内存泄漏问题原理

    2.1堆内存在C代码中的存储方式

    内存泄漏问题只有在使用堆内存的时候才会出现,栈内存不存在内存泄漏问题,因为栈内存会自动分配和释放。C代码中堆内存的申请函数是malloc,常见的内存申请代码如下:

    char *info = NULL; /**转换后的字符串**/

    info = (char*)malloc(NB_MEM_SPD_INFO_MAX_SIZE);

    if( NULL == info)

    {

    (void)tdm_error("malloc error!\n");

    return NB_SA_ERR_HPI_OUT_OF_MEMORY;

    }

    由于malloc函数返回的实际上是一个内存地址,所以保存堆内存的变量一定是一个指针(除非代码编写极其不规范)。再重复一遍,保存堆内存的变量一定是一个指针,这对本文主旨的理解很重要。当然,这个指针可以是单指针,也可以是多重指针。

    malloc函数有很多变种或封装,如g_malloc、g_malloc0、VOS_Malloc等,这些函数最终都会调用malloc函数。

    2.2堆内存的获取方法

    看到本小节标题,可能有些同学有疑惑,上一小节中的malloc函数,不就是堆内存的获取方法吗?的确是,通过malloc函数申请是最直接的获取方法,如果只知道这种堆内存获取方法,就容易掉到坑里了。一般的来讲,堆内存有如下两种获取方法:

    方法一:将函数返回值直接赋给指针,一般表现形式如下:

    char *local_pointer_xx = NULL;

    local_pointer_xx = (char*)function_xx(para_xx, …);

    该类涉及到内存申请的函数,返回值一般都指针类型,例如:

    GSList* g_slist_append (GSList *list, gpointer data)

    方法二:将指针地址作为函数返回参数,通过返回参数保存堆内存地址,一般表现形式如下:

    int ret;

    char *local_pointer_xx = NULL; /**转换后的字符串**/

    ret = (char*)function_xx(..., &local_pointer_xx, ...);

    该类涉及到内存申请的函数,一般都有一个入参是双重指针,例如:

    __STDIO_INLINE _IO_ssize_t

    getline (char **__lineptr, size_t *__n, FILE *__stream)

    前面说通过malloc申请内存,就属于方法一的一个具体表现形式。其实这两类方法的本质是一样的,都是函数内部间接申请了内存,只是传递内存的方法不一样,方法一通过返回值传递内存指针,方法二通过参数传递内存指针。

    2.3内存泄漏三要素

    最常见的内存泄漏问题,包含以下三个要素:

    要素一:函数内有局部指针变量定义;

    要素二:对该局部指针有通过上一小节中“两种堆内存获取方法”之一获取内存;

    要素三:在函数返回前(含正常分支和异常分支)未释放该内存,也未保存到其它全局变量或返回给上一级函数。

    2.4内存释放误区

    稍微使用过C语言编写代码的人,都应该知道堆内存申请之后是需要释放的。但为何还这么容易出现内存泄漏问题呢?一方面,是开发人员经验不足、意识不到位或一时疏忽导致;另一方面,是内存释放误区导致。很多开发人员,认为要释放的内存应该局限于以下两种:

    1)直接使用内存申请函数申请出来的内存,如malloc、g_malloc等;

    2)该开发人员熟悉的接口中,存在内存申请的情况,如iBMC的兄弟,都应该知道调用如下接口需要释放list指向的内存:

    dfl_get_object_list(const char* class_name, GSList **list)

    按照以上思维编写代码,一旦遇到不熟悉的接口中需要释放内存的问题,就完全没有释放内存的意识,内存泄漏问题就自然产生了。

    3. 内存泄漏问题检视方法

    检视内存泄漏问题,关键还是要养成良好的编码检视习惯。与内存泄漏三要素对应,需

    要做到如下三点:

    (1)在函数中看到有局部指针,就要警惕内存泄漏问题,养成进一步排查的习惯

    (2)分析对局部指针的赋值操作,是否属于前面所说的“两种堆内存获取方法”之一,如果是,就要分析函数返回的指针到底指向啥?是全局数据、静态数据还是堆内存?对于不熟悉的接口,要找到对应的接口文档或源代码分析;又或者看看代码中其它地方对该接口的引用,是否进行了内存释放;

    (3)如果确认对局部指针存在内存申请操作,就需要分析该内存的去向,是会被保存在全局变量吗?又或者会被作为函数返回值吗?如果都不是,就需要排查函数所有有”return“的地方,保证内存被正确释放。

    以上就是c语言内存泄漏严重的解决方法的详细内容,更多关于c语言内存泄漏的资料请关注得牛网其它相关文章!

    展开全文
  • cocos2dx之内存泄漏解决机制 大家好,我是Lampard 今天与大家探讨一下cocos中发生内存泄漏解决机制 c++层面的内存泄漏解决 写项目难免会有内存泄漏情况,对于c++层面的代码来说我们可以使用vld这个ku...
  • removeEventListener 移除事件监听 vue 中容易出现内存泄露的几种情况 在 Vue SPA 开发应用,那么就更要当心内存泄漏的问题。因为在 SPA 的设计中,用户使用它时是不需要刷新浏览器的,所以 JavaScript 应用需要...
  • 1.protobuf对象是如何释放(数组)内存的?(本文只针对C++) 毫无疑问是,通过调用析构函数。只要让protobuf定义的对象调用析构函数,无论嵌套了多少层数据、包含了多少个数组都可以释放new出来的内存。 2....
  • 前言Java通过垃圾回收机制,可以自动的管理内存,这对开发人员来说是多么美好的事啊。但垃圾回收器并不是万能的,它能够处理大部分场景下的内存清理、内存泄露以及内存优化。但它也并不是万能的。不...
  • 前言内存泄漏(Memory Leak)是指程序中己动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃 (OOM) 等严重后果。那什么情况下不能被回收呢?目前 java 垃圾...
  • 如果大家在 Linux 或者 macOS 下面运行一段可能导致内存泄露的程序,那么你可能会看到下面这样的情况:而如果你用的系统是 Windows,那么可能电脑直接就卡死了。但是,调试这种 OOM(Out of Memory)的问题有时候是...
  • 前段时间在项目中就用到webview展示大量的新闻资讯页面,然后就惊喜的出现内存泄漏了,于是乎我在网上查了一些资料然后在这里总结一下解决方法,欢迎拍砖。(方法4划重点)。Android混合开发时经常用到WebView加载html...
  • 禁用麻烦的程序是摆脱内存泄漏问题的唯一方法。 转到任务管理器并禁用故障排除程序。 如果您不知道哪些程序正在造成麻烦,请执行以下操作:1、转到“任务管理器”。2、转到“启动”。3、禁用默认情况下不需要运行的...
  • 那么对于这种情况下,由于代码的实现不同就会出现很多种内存泄漏问题(让JVM误以为此对象还在引用中,无法回收,造成内存泄漏)。 1. 静态集合类 如HashMap、LinkedList等等。如果这些容器为静态的,那么它们的生命...
  • 其实这是内存泄露问题,今天脚本之家小编为大家分享安卓内存泄露解决办法,遇到朋友可以节操参考解决问题!绝大部分已经升级到lollipop的android设备都在遭遇一个问题—内存泄露,这是一个轻则后台应用经常被迫关闭...
  • 编译后使用valgrind检测内存泄露[root@localhost string]# valgrind --tool=memcheck --leak-check=full ./mysql==10352== Memcheck, a memory error detector==10352== Copyright (C) 2002-2009, and GNU GPL'd, by...
  • 同样的深度学习模型在linux运行没有遇到内存泄漏的问题,迁移到Windows就出现了问题。 报错信息为:numpy.core._exceptions.memoryerror unable to allocate 查了一下GPU Memory使用量没有爆(爆也不是提示这个信息...
  • ##引起内存泄漏的原因 意外的全局变量 由于 js 对未声明变量的处理方式是在全局对象上创建该变量的引用。如果在浏览器中,全局对象就是 window 对象。变量在窗口关闭或重新刷新页面之前都不会被释放,如果未声明的...
  • Android开发 单例模式导致内存泄露存在内存泄露问题的一些代码片段像下面这样:2.public class Util {3.4. private Context mContext;5.private static Util sInstance;6.7. private Util(Context context) {8. this...
  • 在handler使用中遇到了内存泄漏,一脸懵逼上网查阅资料后得到解决,希望记录下来以后翻阅 原因分析: 非静态、匿名内部类会隐式持有外部类的引用,这会导致一个什么结果呢,当Handler以非静态或匿名内部类的的方式...
  • 问题出现 首先了解声明是闭包?比较简单的开源这里理解,函数中嵌套一个函数;比如函数1是函数2的父函数,那么... 上述就是解决闭包内存泄漏的两个方法,希望能帮助你,有更好的解决方案可以留在评论区给大家一起分享!
  • 之所以撰写这篇文章是由于前段时间花费了非常大的精力在已经成熟的代码上再去处理memory leak问题。写此的目的是希望我们应该养成良好的编码习惯,尽可能的避免这种问题,由于当你对着...内存泄漏并不是指内存在物理...
  • JAVA内存泄漏解决日记

    2021-02-28 13:01:47
    原标题:JAVA内存泄漏解决日记最近解决了一次线上内存泄漏的BUG,将解决问题的过程记录如下:1.登录服务器查询JAVA进程heap的概要信息,使用命令:jmap –heap 3772,结果如下图所示: 从上图可见,老年代已使用99%...
  • 如何解决Python2的内存泄漏问题python本身不会造成内存泄露,如果用的C/C++写的模块(包),如果处理不好,可能会造成内存泄露,但是也是C/C++的模块造成的欢迎来到四十五资源网,python本身不会造成内存泄露,如果用的C/...
  • 今天小编跟大家讲解下有关PHP脚本内存泄露导致Apache频繁宕机解决方法 ,相信小伙伴们对这个话题应该也很关注吧,小编也收集到了有关PHP脚本内存泄露导致Apache频繁宕机解决方法 的相关资料,希望小伙伴会喜欢也能够...
  • 解决win10桌面管理器内存泄漏问题 1.打开控制面板 2.点击硬件和声音 3.点击电源选项 4.选择关闭笔记本计算机盖的功能 5.更改当前不可更改的设置 6.把快速启动关闭
  • 最近正在熟悉Java内存泄漏的相关知识,上网查阅了一些资料,在此做个整理算是对收获的一些总结,希望能对各位有所帮助,有问题可以文末留言探讨、补充。 如下是整篇文章的结构,所需阅读时间大约20min 1. ...
  • Python内存泄漏和内存溢出的解决方法发布时间:2020-10-30 23:08:34来源:亿速云阅读:92作者:Leah这篇文章将为大家详细讲解有关Python内存泄漏和内存溢出的解决方法,文章内容质量较高,因此小编分享给大家做个...
  • 有点像内存泄漏的问题,但是进程里面也看不出来那个进程占用的最大。现在天天重启对于开发来说太难受了。 尝试解决方案有: 什么输入法,显卡设置,显卡驱动,卸载全家桶,关闭supperfech服务、卸载windows...
  • Handler泄漏问题

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 203,659
精华内容 81,463
关键字:

内存泄漏怎么解决