Android 优化二 Java内存分配机制及内存泄漏

Stella981
• 阅读 605

Java内存分配机制及内存泄漏 目录介绍

  • 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.本人写的综合案例

  • 案例

  • 说明及截图

  • 模块:新闻,音乐,视频,图片,唐诗宋词,快递,天气,记事本,阅读器等等

  • 接口:七牛,阿里云,天行,干货集中营,极速数据,追书神器等等

思维导图

Android 优化二 Java内存分配机制及内存泄漏

1.JVM内存管理

1.1 JVM内存管理 Android 优化二 Java内存分配机制及内存泄漏

1.2 Java采用GC进行内存管理。

  • Android虚拟机的垃圾回收采用的是根搜索算法。GC会从根节点(GC Roots)开始对heap进行遍历。到最后,部分没有直接或者间接引用到GC Roots的就是需要回收的垃圾,会被GC回收掉。而内存泄漏出现的原因就是存在了无效的引用,导致本来需要被GC的对象没有被回收掉。 深入的JVM内存管理知识,推荐《深入理解Java虚拟机》。

2.JVM内存分配的几种策略。

2.1 静态的

  • 静态的存储区,内存在程序编译的时候就已经分配好了,这块内存在程序整个运行期间都一直存在 它主要存放静态数据、全局的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();进行内存回收

  • 我们知道可以调用 System.gc();进行内存回收,但是GC不一定会执行。面对GC的机制,我们是否无能为力?其实我们可以通过声明一些引用标记来让GC更好对内存进行回收。

Android 优化二 Java内存分配机制及内存泄漏

  • 小技巧 成员变量全部存储在堆中(包括基本数据类型,引用及引用的对象实体),因为他们属于类,类对象最终还是要被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 优化二 Java内存分配机制及内存泄漏

  • 软引用和弱引用 在Android应用的开发中,为了防止内存溢出,在处理一些占用内存大而且声明周期较长的对象时候,可以尽量应用软引用和弱引用技术 软/弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收器回收,Java虚拟机就会把这个软引用加入到与之关联的引用队列中。 利用这个队列可以得知被回收的软/弱引用的对象列表,从而为缓冲器清除已失效的软/弱引用。

  • 内存泄漏的原因: 堆内存中的长生命周期的对象持有短生命周期对象的强/软引用,尽管短生命周期对象已经不再需要,但是因为长生命周期对象持有它的引用而导致不能被回收,这就是Java中内存泄露的根本原因

4.内存泄漏简单介绍

4.1 内存泄漏的定义

  • 当一个对象已经不需要使用了,本该被回收时,而有另外一个正在使用的对象持有它的引用,从而导致了对象不能被GC回收。这种导致了本该被回收的对象不能被回收而停留在堆内存中,就产生了内存泄漏

4.2 内存泄漏与内存溢出的区别

  • 内存泄漏(Memory Leak) 进程中某些对象已经没有使用的价值了,但是他们却还可以直接或间接地被引用到GC Root导致无法回收。当内存泄漏过多的时候,再加上应用本身占用的内存,日积月累最终就会导致内存溢出OOM

  • 内存溢出(OOM) 当应用的heap资源超过了Dalvik虚拟机分配的内存就会内存溢出

4.3 内存泄漏带来的影响

  • 应用卡顿 泄漏的内存影响了GC的内存分配,过多的内存泄漏会影响应用的执行效率

  • 应用异常(OOM) 过多的内存泄漏,最终会导致 Dalvik分配的内存,出现OOM

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。

其他说明

点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
爱库里 爱库里
3年前
图文并茂讲清楚 JavaScript 内存管理
作为一个JavaScript的开发者,大多数情况下你可能不会担心内存管理问题,因为JavaScript引擎会帮你处理这些。但是在开发过程中,你或多或少的会遇到一些相关的问题,比如内存泄漏等,只有了解了内存分配的工作机制,你才会知道如何去解决这些问题。在这篇文章中,我将会向你介绍内存分配和垃圾收集的机制,以及如何避免一些常见的内存泄漏的
Wesley13 Wesley13
2年前
Unity优化之
当我们来创建一个对象、字符串或数组时,我们需要从称为堆的中央池中为其分配内存来存储它。当它不再被使用时,我们又需要来释放这块内存便于重复使用。在以前这个过程通常需要我们通过适当的函数调用显式地分配和释放块内存来实现。但现在,运行时系统如Unity的mono引擎将自动地为我们管理内存。自动内存管理比显式分配/释放需要更少的编码工作,大大减少了内存泄漏的可能性(
Wesley13 Wesley13
2年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
2年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Wesley13 Wesley13
2年前
Java内存区域与内存溢出异常
Java的内存管理是一个老生常谈的问题,虽然Java号称可以自动管理自己的内存,使程序员从内存管理的围墙解放出来,但是一连串的内存泄漏和溢出方面的问题,使得我们不得不去深入了解Java的内存管理机制。本篇文章将从Java的内存区域开始剖析Jvm的内存机制,阐述内存溢出异常产生的原因。运行时数据区域众说周知,Java程序是运行在Java虚拟机
Stella981 Stella981
2年前
JScript的内存泄漏
当一个系统没有妥善地管理它的内存分配时,就被称为内存泄漏,内存泄漏是一个bug,这问题会导致性能下降和运行错误。微软的InternetExplorer有许多的泄漏问题(https://www.oschina.net/action/GoToLink?urlhttp%3A%2F%2Fmsdn.microsoft.com%2Flibrary%2Fdef
Wesley13 Wesley13
2年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Wesley13 Wesley13
2年前
Java内存泄漏解析!
前言:内存管理是Java最重要的优势之一,你只需创建对象,Java垃圾收集器会自动负责分配和释放内存。但是,情况并不那么简单,因为在Java应用程序中经常发生内存泄漏。本章会说明什么是内存泄漏,为什么发生,以及如何防止它们。什么是内存泄漏?内存泄漏的定义:应用程序不再使用的对象,垃圾收集器却无法删除它们,因为它们正在被引用。为了理
Python进阶者 Python进阶者
3个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这