java避免内存泄露_Java防止非静态内部类内存泄漏

内存泄漏

一个不会被使用的对象,因为另一个正在使用的对象持有该对象的引用,导致它不能正常被回收,而停留在堆内存中,从而导致内存泄漏。

最坏的情况下,由于大量的内存泄漏,最终导致jvm的内存耗尽,致使程序奔溃。也可能会导致内存空间不足,jvm出现频繁的GC。

代码示例

import java.util.ArrayList;

class OuterClass

{

private int[] data;

public OuterClass(int size)

{

data = new int[size];

}

class InnerClass

{

}

InnerClass getInnerClassObject()

{

return new InnerClass();

}

}

public class MemoryLeak

{

public static void main(String[] args)

{

ArrayList al = new ArrayList<>();

int counter = 0;

while (true)

{

al.add(new OuterClass(100000).getInnerClassObject());

System.out.println(counter++);

}

}

}

执行以上代码,输出结果,最终导致了堆内存溢出。

7639

7640

7641

7642

7643

7644

7645

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space

at EnclosingClass.(MemoryLeak.java:9)

at MemoryLeak.main(MemoryLeak.java:30)

原因分析

我们使用java提供的工具javap,可以对编译生成的.class文件做分析。也可以使用一些反编译工具对生成的.class反编译,也可以看到内部类的代码实现。

javap OuterClass$InnerClass

输出类似于:

Compiled from "OuterClass.java"

public class OuterClass$InnerClass {

final OuterClass this$0;

public OuterClass$InnerClass(OuterClass);

}

可以看到内部类InnerClass存在一个this$0的OuterClass的变量,此变量是通过InnerClass的构造函数传进来的。

示例代码中创建了一个数组列表ArrayList,它将用来存放InnerClass的对象。生成InnerClass对象前,需要先构造OuterClass。OuterClass构造时默认创建了一个100000大小的整型数组。相当于一个初始化的OuterClass默认占用10000个int整型的空间。在MemoryLeak,通过循环while不断向a1添加InnerClass对象。对于每次循环来说new OuterClass后,就不会再使用OuterClass对象。但通过分析内部了的实现,即使OuterClass对象不会再被使用,内部类InnerClass对象里还是保存了大对象OuterClass,导致OuterClass的生命周期是和InnerClass一样,最终导致内存泄漏。

非静态内部类使用注意

1、如果外部类是一个大对象,必须要谨慎使用非静态内部类,特别时生命周期长的非静态内部类,这样容易造成内存溢出OutOfMemoryError。

2、之所以强调非静态,对于静态内部类来说,它的内部实现是不存放外部类的,所以再合理编码的情况下,使用静态内部类。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值