【内存泄露】Memory Leaks 内存优化
什么是内存泄露
为什么会发生内存泄露
发生内存泄漏的常见场景
静态集合类的使用
public class Test {static ArrayList<Person> list = new ArrayList<Person>();//list中引用的对象在应用整个生命周期中都不会被释放public static void main(String[] args) {for (int i = 1; i < 10; i++) {Person person = new Person("" + i);list.add(person);person = null;//这行代码的作用仅仅是将【变量person】指向null(之前是指向堆内存中的Person对象),但是这时堆内存中的【Person对象】并不会被回收,因为它被list强引用了}for (Person person : list) {System.out.println(person);//所有Person对象都没有被回收!!!}}
}class Person {public String name;public Person(String name) {this.name = name;}@Overridepublic String toString() {return name;}
}
public class Test {
static ArrayList<Person> list = new ArrayList<Person>();//list中引用的对象在应用整个生命周期中都不会被释放
public static void main(String[] args) {
for (int i = 1; i < 10; i++) {
Person person = new Person("" + i);
list.add(person);
person = null;//这行代码的作用仅仅是将【变量person】指向null(之前是指向堆内存中的Person对象),但是这时堆内存中的【Person对象】并不会被回收,因为它被list强引用了
}
for (Person person : list) {
System.out.println(person);//所有Person对象都没有被回收!!!
}
}
}
class Person {
public String name;
public Person(String name) {
this.name = name;
}
@Override
public String toString() {
return name;
}
}
Listener、Receiver等监听器的引用
public class Test {public static void main(String[] args) {B b = new B();//被监听者,如ActivityA a = new A();//监听者,如BroadcastReceiverb.register(a);//在b中注册【a监听器】,通常register内部的操作是:将a的引用传给b的成员变量,进而长期持有a的引用a = null;//虽然将监听器a设为null,但是监听器对象A并没有被回收,因为它被B引用了b.show();//监听器工作了b.unregister();//用完要注销掉}
}interface Listener {public void listen();
}class A implements Listener {//监听者,如BroadcastReceiver@Overridepublic void listen() {System.out.println("监听器工作了");}
}class B {//被监听者,如ActivityListener listener;public void register(Listener listener) {//B持有了Listener的引用,除非在B内部将其设为null,否则listener将不会被回收this.listener = listener;}public void unregister() {listener = null;}public void show() {if (listener != null) listener.listen();}
}
public class Test {
public static void main(String[] args) {
B b = new B();//被监听者,如Activity
A a = new A();//监听者,如BroadcastReceiver
b.register(a);//在b中注册【a监听器】,通常register内部的操作是:将a的引用传给b的成员变量,进而长期持有a的引用
a = null;//虽然将监听器a设为null,但是监听器对象A并没有被回收,因为它被B引用了
b.show();//监听器工作了
b.unregister();//用完要注销掉
}
}
interface Listener {
public void listen();
}
class A implements Listener {//监听者,如BroadcastReceiver
@Override
public void listen() {
System.out.println("监听器工作了");
}
}
class B {//被监听者,如Activity
Listener listener;
public void register(Listener listener) {//B持有了Listener的引用,除非在B内部将其设为null,否则listener将不会被回收
this.listener = listener;
}
public void unregister() {
listener = null;
}
public void show() {
if (listener != null) listener.listen();
}
}
非静态内部类对外部类的引用
/*** 测试非静态内部类导致内存泄漏的问题*/
public class MemoryLeaksActivity extends Activity {TextView textView;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);textView = new TextView(this);setContentView(textView);String startTime = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss SSS", Locale.getDefault()).format(new Date());textView.setText("开始休息 " + startTime);//匿名内部类,如果在Activity销毁前线程的任务还未完成,将导致Activity的内存资源无法回收,造成内存泄漏new Thread(() -> {SystemClock.sleep(1000 * 5);String endTime = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss SSS", Locale.getDefault()).format(new Date());Log.i("bqt", "【结束休息】" + endTime);//即使Activity【onDestroy被回调了】,这条日志仍会打出来//runOnUiThread(() -> textView.append("\n结束休息 " + endTime));}).start();}@Overrideprotected void onDestroy() {super.onDestroy();Log.i("bqt", "【onDestroy被回调了】");}
}
/**
* 测试非静态内部类导致内存泄漏的问题
*/
public class MemoryLeaksActivity extends Activity {
TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
textView = new TextView(this);
setContentView(textView);
String startTime = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss SSS", Locale.getDefault()).format(new Date());
textView.setText("开始休息 " + startTime);
//匿名内部类,如果在Activity销毁前线程的任务还未完成,将导致Activity的内存资源无法回收,造成内存泄漏
new Thread(() -> {
SystemClock.sleep(1000 * 5);
String endTime = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss SSS", Locale.getDefault()).format(new Date());
Log.i("bqt", "【结束休息】" + endTime);//即使Activity【onDestroy被回调了】,这条日志仍会打出来
//runOnUiThread(() -> textView.append("\n结束休息 " + endTime));
}).start();
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.i("bqt", "【onDestroy被回调了】");
}
}
/*** 测试使用静态内部类避免导致内存泄漏*/
public class MemoryLeaksActivity extends Activity {TextView textView;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);textView = new TextView(this);setContentView(textView);String startTime = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss SSS", Locale.getDefault()).format(new Date());textView.setText("开始休息 " + startTime);new MyThread(this).start();}@Overrideprotected void onDestroy() {super.onDestroy();Log.i("bqt", "【onDestroy被回调了】");}//静态内部类private static class MyThread extends Thread {SoftReference<Activity> context;MyThread(Activity activity) {context = new SoftReference<>(activity);}@Overridepublic void run() {SystemClock.sleep(1000 * 15);String endTime = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss SSS", Locale.getDefault()).format(new Date());Log.i("bqt", "【结束休息】" + endTime);//即使Activity【onDestroy被回调了】,这条日志仍会打出来if (context.get() != null) {context.get().runOnUiThread(() -> Toast.makeText(context.get(), "结束休息", Toast.LENGTH_SHORT).show());}}}
}
/**
* 测试使用静态内部类避免导致内存泄漏
*/
public class MemoryLeaksActivity extends Activity {
TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
textView = new TextView(this);
setContentView(textView);
String startTime = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss SSS", Locale.getDefault()).format(new Date());
textView.setText("开始休息 " + startTime);
new MyThread(this).start();
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.i("bqt", "【onDestroy被回调了】");
}
//静态内部类
private static class MyThread extends Thread {
SoftReference<Activity> context;
MyThread(Activity activity) {
context = new SoftReference<>(activity);
}
@Override
public void run() {
SystemClock.sleep(1000 * 15);
String endTime = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss SSS", Locale.getDefault()).format(new Date());
Log.i("bqt", "【结束休息】" + endTime);//即使Activity【onDestroy被回调了】,这条日志仍会打出来
if (context.get() != null) {
context.get().runOnUiThread(() -> Toast.makeText(context.get(), "结束休息", Toast.LENGTH_SHORT).show());
}
}
}
}
单例模式初始化后的对象
数据库、网络、io流等连接
优化内存的方法
【内存泄露】Memory Leaks 内存优化相关推荐
- VC++6.0 内存泄露(Memory Leaks)征兆1
我在调试[用VC++6.0的MFC框架写的eWSAuditSys_VC6应用程序]时,突然出现了一下莫名其妙的东西.我将output中的内容分为上半部分和下半部分进行展示,其中下半部分的内容是关键 o ...
- SQL Server 内存泄露(memory leak)——游标导致的内存问题
原文:SQL Server 内存泄露(memory leak)--游标导致的内存问题 转自:http://blogs.msdn.com/b/apgcdsd/archive/2011/07/01/sql ...
- 内存溢出(Memory Overflow)和内存泄露(Memory Leak)的区别
内存泄漏指你用malloc或new申请了一块内存,但是没有通过free或delete将内存释放,导致这块内存一直处于占用状态 内存溢出指你申请了10个字节的空间,但是你在这个空间写入11或以上字节的数 ...
- Detected memory leaks!内存泄漏,溢出,内存越界问题分析
应用程序发生 Detected memory leaks!内存泄漏 一直程序员面对的是一个很痛苦的问题,要查出泄漏的地方有时候需要大半天甚至更长时间.这里讲讲我的一些查找内存泄漏以及避免内存泄漏的一些 ...
- 转载浅谈MFC内存泄露检测及内存越界访问保护机制
2019独角兽企业重金招聘Python工程师标准>>> 本文所有代码均在VC2008下编译.调试.如果您使用的编译器不同,结果可能会有差别,但本文讲述的原理对于大部分编译器应该是相似 ...
- java 多线程 内存泄露_关于内存泄露的总结
大致先分为五个小模块: 1.什么是内存泄漏 2.有哪些情况会导致内存泄漏切如何解决 3.如何检测内存泄漏 4.Java得基本数据类型和占用字节 5.什么是内存溢出和解决办法 一.什么是内存泄漏(Mem ...
- JavaScript内存泄露,闭包内存泄露如何解决
转载于:JavaScript内存泄露,闭包内存泄露如何解决 - 一粒一世界 - 博客园 JavaScript 内存泄露的4种方式及如何避免 简介 什么是内存泄露? JavaScript 内存管理 Ja ...
- drools规则引擎因为内存泄露导致的内存溢出
进入这个问题之前,先了解一下drools: 在很多行业应用中比如银行.保险领域,业务规则往往非常复杂,并且规则处于不断更新变化中,而现有很多系统做法基本上都是将业务规则绑定在程序代码中. 主要存在的问 ...
- 性能优化之内存泄露(Memory Leak)常用分析工具(另3种)
1 LeakCanary(最常用,能监控整个App内存泄漏情况) 1.1 使用LeakCanary // 仅在debug包启用LeakCanary debugImplementation 'com.s ...
最新文章
- LeetCode 200. Number of Islands--c++ dfs解法
- 提高页面显示速度的秘技
- VMware演示手机虚拟化
- 数据库基础知识——DDL语言
- linux mint 19界面美化,安装完 LinuxMint 19.3 后必做的10件事
- 漫步数理统计三十三——采样与统计量
- 4.4 一个完整的Google Maps应用
- Android开发之修改Chrome书签
- 《战争论》第四篇《战斗》的主要内容
- pytorch tensor操作:tensor与numpy转换
- selenium-webdriver层级定位元素
- JS逆向---获取某知名外卖平台数据(_token)
- 应用程序正常初始化(0xc0150002)失败
- 深入理解Attention及变种(二)
- 网页版在线公式编辑器
- pycharm和webstorm下载安装流程
- Robot Framework自动化测试教程-通过RIDE创建工程、测试套、测试用例、测试资源、变量文件,引入测试库
- 基于CAN总线步进电机驱动器设计
- 第十四章:Element-ui组件库
- 解决pxe网络批量安装部署linux遇到的问题和解决方法