内存泄漏3____内存泄漏, 内存溢出的区别与关系__内存抖动

本文深入解析内存泄漏(memoryleak)与溢出(outofmemory)的区别,探讨垃圾回收机制如何自动管理堆内存,揭示内存抖动的根源及影响,如卡顿和OOM。文章通过实例说明字符串拼接和频繁对象创建如何引发内存抖动,并提供优化建议。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

泄漏  memory leak  是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄露危害可以忽略,
但内存泄漏堆积后, 会变得很严重,无论有多少空间,迟早会被占光。

memory leak 最终会导致 OOM (out of memory)。 看一个图


一. 溢出  out of  memory  是指程序在申请内存空间时, 没有足够的空间供其使用,出现OOM, 比如申请了1M的图片空间,但它要存一个5M大小的图片,就是内存溢出。
 

分析: 垃圾回收就是一种自动在堆内存中找出哪些对象在被使用, 哪些对象没被使用,并且将没被使用的删掉的机制。

注意:JVM有GC机制, C++才需要手动回收。

二. 接下来了解 内存抖动

短时间内有大量对象创建销毁导致,它会伴随着频繁的GC.

我们在AS上运行Android工程时,点击Profile 'app' 按钮,可以看到很多系统配置信息

, 点击后,可看到下方如图所示

内存抖动可以用 如下图所示:  图表跳动很强烈

2.1 内存抖动的影响: 卡顿

2.2  内存抖动的影响:OOM

应用的GC运行时,会将程序所有线程挂起,因为一边在回收垃圾,一边在产生垃圾, 会导致回收还没有产生快,垃圾越来越多。

看一个图,形象表示内存使用情况:

2.3 内存抖动 的原因有:

1. 字符串的拼接, 例如

for(int i=0;i<values.length;i++){
            /**
             * 使用+号, 看起来是修改了值,其实是把变量指向的内存区域,指向的对象发生了变化
             * 而对于字符串本身是不变的, +号是做了StringBuilder()的append()方法
             */
            result +=values[i];
            //以下写法与 上句效果相同,  但是会创建大量临时对象
            //result = new StringBuilder().append(result).append(values[i]).toString();

            // 第三步,通过javap  -c com.rd.memory.TestMemory 命令行来查看class文件的指令
}

2. 有的方法会创建新的对象,例如 Color.parseColor()方法, 会创建一个新的String对象。

    此方法 如果是放在循环调用里(如onDraw()),将导致产生很多String对象。 

解决方法: 用 paint.setColor(colorInts[i]) 代替 paint.setColor(Color.parseColor(color[i])), 

也就是说传递 int类型数组的参数,  不是字符串数组再转化的参数

3. 内存抖动的根本原因是 创建大量的临时对象, 这些对象用完一次就不要了, 最常见是在 for循环中 创建String对象。

   不是说创建大量对象就一定会内存抖动。 

4. 看一个例子,

public class TestMemory {


    public static void main(String[] args) {
        addStr(new String[]{"cpu", "memory", "network"});
    }

    public static String addStr(String[] values){
        //字符串定义了值,是不可变的
        String result = "";
        for(int i=0;i<values.length;i++){
            /**
             * 使用+号, 看起来是修改了值,其实是把变量指向的内存区域,指向的对象发生了变化
             * 而对于字符串本身是不变的, +号是做了StringBuilder()的append()方法
             */
            result +=values[i];
            //以下写法与 上句效果相同,  但是会创建大量临时对象
            //result = new StringBuilder().append(result).append(values[i]).toString();

            // 第三步,通过javap  -c com.rd.memory.TestMemory 命令行来查看class文件的指令
        }
        return result;
    }
}

用 javap 执行如下命令,可以看到TestMemory执行的指令过程

在profile界面中, 点击Record按钮,开始记录一段时间应用的内存情况

内存泄漏是造成内存溢出的主要原因之一。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值