Java内存分配机制及内存泄漏 目录介绍php
- 1.JVM内存管理
- 1.1 JVM内存管理图
- 1.2 Java采用GC进行内存管理。
- 2.JVM内存分配的几种策略
- 2.1 静态的
- 2.2 栈式的
- 2.3 堆式的
- 2.4 堆和栈的区别
- 2.5 得出结论
- 2.6 举个例子
- 2.7 调用 System.gc();进行内存回收
- 3.GC简单介绍
- 3.1 内存垃圾回收机制
- 3.2 关于GC介绍
- 3.3 如何监听GC过程
- 3.4 GC过程与对象的引用类型关系
- 4.内存泄漏简单介绍
- 4.1 内存泄漏的定义
- 4.2 内存泄漏与内存溢出的区别
- 4.3 内存泄漏带来的影响
- 4.4 典型内存泄漏案例
关于内存泄漏笔记
0.本人写的综合案例
-
-
- 模块:新闻,音乐,视频,图片,唐诗宋词,快递,天气,记事本,阅读器等等
- 接口:七牛,阿里云,天行,干货集中营,极速数据,追书神器等等
思惟导图

1.JVM内存管理
1.1 JVM内存管理
java
1.2 Java采用GC进行内存管理。git
- Android虚拟机的垃圾回收采用的是根搜索算法。GC会从根节点(GC Roots)开始对heap进行遍历。到最后,部分没有直接或者间接引用到GC Roots的就是须要回收的垃圾,会被GC回收掉。而内存泄漏出现的缘由就是存在了无效的引用,致使原本须要被GC的对象没有被回收掉。 深刻的JVM内存管理知识,推荐《深刻理解Java虚拟机》。
2.JVM内存分配的几种策略。
2.1 静态的github
- 静态的存储区,内存在程序编译的时候就已经分配好了,这块内存在程序整个运行期间都一直存在 它主要存放静态数据、全局的static数据和一些常量。
2.2 栈式的算法
- 在执行方法时,方法一些内部变量的存储均可以放在栈上面建立,方法执行结束的时候这些存储单元就会自动被注释掉。栈 内存包括分配的运算速度很快,由于内在在处理器里面。固然容量有限,而且栈式一块连续的内存区域,大小是由操做系统决定的,他先进后出,进出完成不会产生碎片,运行效率高且稳定
2.3 堆式的数组
- 也叫动态内存 。咱们一般使用new 来申请分配一个内存。这里也是咱们讨论内存泄漏优化的关键存储区。GC会根据内存的使用状况,对堆内存里的垃圾内存进行回收。堆内存是一块不连续的内存区域,若是频繁地new/remove会形成大量的内存碎片,GC频繁的回收,致使内存抖动,这也会消耗咱们应用的性能
2.4 堆和栈的区别并发
- 在函数中(说明是局部变量)定义的一些基本类型的变量和对象的引用变量都是在函数的栈内存中分配。
- 当在一段代码块中定义一个变量时,java就在栈中为这个变量分配内存空间,当超过变量的做用域后,java会自动释放掉为该变量分配的内存空间,该内存空间能够马上被另做他用。
- 堆内存用于存放全部由new建立的对象(内容包括该对象其中的全部成员变量)和数组。在堆中分配的内存,由java虚拟机自动垃圾回收器来管理。
- 在堆中产生了一个数组或者对象后,还能够在栈中定义一个特殊的变量,这个变量的取值等于数组或者对象在堆内存中的首地址,在栈中的这个特殊的变量就变成了数组或者对象的引用变量,之后就能够在程序中使用栈内存中的引用变量来访问堆中的数组或者对象,引用变量至关于为数组或者对象起的一个别名,或者代号。
2.5 得出结论函数
- 1.局部变量的基本数据类型和引用,存储于栈中,引用的对象实体存储于堆中。由于它们属于方法中的变量,生命周期随方法而结束。 2.成员变量所有存储与堆中(包括基本数据类型,引用和引用的对象实体),由于它们属于类,类对象终究是要被new出来使用的。 3.咱们所说的内存泄露,只针对堆内存,他们存放的就是引用指向的对象实体。
2.6 举个例子工具
public class Sample() {
int s1 = 0;
Sample mSample1 = new Sample();
public void method() {
int s2 = 1;
Sample mSample2 = new Sample();
}
}
Sample mSample3 = new Sample();
Sample 类的局部变量 s2 和引用变量 mSample2 都是存在于栈中,但 mSample2 指向的对象是存在于堆上的。
mSample3 指向的对象实体存放在堆上,包括这个对象的全部成员变量 s1 和 mSample1,而它本身存在于栈中。
2.7 调用 System.gc();进行内存回收post
- 咱们知道能够调用 System.gc();进行内存回收,可是GC不必定会执行。面对GC的机制,咱们是否无能为力?其实咱们能够经过声明一些引用标记来让GC更好对内存进行回收。

- 小技巧 成员变量所有存储在堆中(包括基本数据类型,引用及引用的对象实体),由于他们属于类,类对象最终仍是要被new出来的 局部变量的基本数据类型和引用存在栈中,应用的对象实体存储在堆中。由于它们属于方法当中的变量,生命周期会随着方法一块儿结束
3.GC工做原理
3.1 内存垃圾回收机制
- 是从程序的主要运行对象(如静态对象/寄存器/栈上指向的堆内存对象等)开始检查引用链,当遍历一遍后获得上述这些没法回收的对象和他们所引用的对象链,组成没法回收的对象集合,而其余孤立对象(集)就做为垃圾回收
- GC为了可以正确释放对象,必须监控每个对象的运行状态,包括对象的申请、引用、被引用、赋值等,GC都须要进行监控。监视对象状态是为了更加准确地、及时地释放对象,而释放对象的根本原则就是该对象再也不被引用。
3.2 关于GC介绍
- 有几个函数能够访问GC,例如运行GC的函数System.gc(),可是根据Java语言规范定义,该函数不保证JVM的垃圾收集器必定会执行。由于不一样的JVM实现者可能使用不一样的算法管理GC
- 一般GC的线程的优先级别较低。JVM调用GC的策略也有不少种,有的是内存使用到达必定程度时,GC才开始工做,也有定时执行的,有的是平缓执行GC,有的是中断式执行GC。但一般来讲,咱们不须要关心这些。
- 经过关键字 new 为每一个对象申请内存空间 (基本类型除外),全部的对象都在堆 (Heap)中分配空间
3.3 如何监听GC过程
- 系统每进行一次GC操做时,都会在LogCat中打印一条日志,咱们只要去分析这条日志就能够了,日志的基本格式以下 D/dalvikvm: <GC_Reason> <Amount_freed>, <Heap_stats>, <Pause_time> 第一部分GC_Reason,这个是触发此次GC操做的
缘由,通常状况下一共有如下几种触发GC操做的缘由:
- GC_CONCURRENT: 当咱们应用程序的堆内存快要满的时候,系统会自动触发GC操做来释放内存。
- GC_FOR_MALLOC: 当咱们的应用程序须要分配更多内存,但是现有内存已经不足的时候,系统会进行GC操做来释放内存。
- GC_HPROF_DUMP_HEAP: 当生成HPROF文件的时候,系统会进行GC操做,关于HPROF文件咱们下面会讲到。
- GC_EXPLICIT: 这种状况就是咱们刚才提到过的,主动通知系统去进行GC操做,好比调用System.gc()方法来通知系统。或者在DDMS中,经过工具按钮也是能够显式地告诉系统进行GC操做的。
第二部分Amount_freed,表示系统经过此次GC操做释放了多少内存 第三部分Heap_stats中会显示当前内存的空闲比例以及使用状况(活动对象所占内存 / 当前程序总内存) 第四部分Pause_time表示此次GC操做致使应用程序暂停的时间。关于这个暂停的时间,Android在2.3的版本当中进行过一次优化,在2.3以前GC操做是不能并发进行的,也就是系统正在进行GC,那么应用程序就只能阻塞住等待GC结束。虽然说这个阻塞的过程并不会很长,也就是几百毫秒,可是用户在使用咱们的程序时仍是有可能会感受到略微的卡顿。而自2.3以后,GC操做改为了并发的方式进行,就是说GC的过程当中不会影响到应用程序的正常运行,可是在GC操做的开始和结束的时候会短暂阻塞一段时间,不过优化到这种程度,用户已是彻底没法察觉到了
3.4 GC过程与对象的引用类型关系
- Java对引用的分类Strong reference, SoftReference, WeakReference, PhatomReference

-
软引用和弱引用 在Android应用的开发中,为了防止内存溢出,在处理一些占用内存大并且声明周期较长的对象时候,能够尽可能应用软引用和弱引用技术 软/弱引用能够和一个引用队列(ReferenceQueue)联合使用,若是软引用所引用的对象被垃圾回收器回收,Java虚拟机就会把这个软引用加入到与之关联的引用队列中。 利用这个队列能够得知被回收的软/弱引用的对象列表,从而为缓冲器清除已失效的软/弱引用。
-
内存泄漏的缘由: 堆内存中的长生命周期的对象持有短生命周期对象的强/软引用,尽管短生命周期对象已经再也不须要,可是由于长生命周期对象持有它的引用而致使不能被回收,这就是Java中内存泄露的根本缘由
4.内存泄漏简单介绍
4.1 内存泄漏的定义
- 当一个对象已经不须要使用了,本该被回收时,而有另一个正在使用的对象持有它的引用,从而致使了对象不能被GC回收。这种致使了本该被回收的对象不能被回收而停留在堆内存中,就产生了内存泄漏
4.2 内存泄漏与内存溢出的区别
4.3 内存泄漏带来的影响
4.4 典型内存泄漏案例
Vector v = new Vector(10);
for (int i = 1; i < 100; i++) {
Object o = new Object();
v.add(o);
o = null;
}
- 分析 在这个例子中,咱们循环申请Object对象,并将所申请的对象放入一个 Vector 中,若是咱们仅仅释放引用自己,那么 Vector 仍然引用该对象,因此这个对象对 GC 来讲是不可回收的。所以,若是对象加入到Vector 后,还必须从 Vector 中删除,最简单的方法就是将 Vector 对象设置为 null。
其余说明