JAVA回收机制与Android的OOM

这几天做课件看了不少JVM相关的知识怕自己忘记。大部分理论知识都是来自网上其他博客的引用,我把自己想要重点记录的记了下来。

                                                      

RAM随机存取存储器临时存储的地方,关机后数据消除,也叫主存。图是网上找的,JVM的内存模型图,Dalvik是一个特殊的JVM所以需要先从了解JVM开始。

我们需要了解虚拟内存这个概念。

虚拟内存概念:呈现出比实际拥有大得多的内存量,使得每个应用程序认为自己拥有连续且可用的空间。

我来解释下这段话64位系统中,理论寻址次数为2∧64,实际的寻址次数为2∧48。存数据是需要地址的,寻址的次数就等于虚拟内存的大小。虚拟地址会对应一个物理地址,但是这个物理地址并不连续。如果物理地址不够用,就会进行交换空间操作把内存上释放某些进程占用但未使用的部分或者所有物理内存,被释放的部分储存在磁盘上

我看到过一个形象的比喻来说交换空间,一列火车从北京到上海,你只需要3公里的铁路就可以办到。

程序计数器:程序计数器是一块很小的内存空间,它是线程私有的,可以认作为当前线程的行号指示器。

Java栈(虚拟机栈):线程私有,生命周期与相同,就是我们平时说的栈,栈描述的是Java方法执行的内存模型。以帧为单位出入,存储局部变量,操作数栈,动态链接,方法返回地址等。

本地方法栈:执行调用C/C++的地方。

:Java虚拟机管理内存最大的一块内存区域,因为堆存放的对象是线程共享的,所以多线程的时候也需要同步机制。是一个完全二叉树。

方法区:用于存储已被虚拟机加载的类信息、常量、静态变量,如static修饰的变量加载类的时候就被加载到方法区中。

本文不主要记录内存模型,只是注意2个地方:

1.7之前运行常量池在方法区的永生代中,之后在堆中。

2.永生代在8被去除,改为元空间。

元数据包括:class ,enum(枚举),interface(接口),元数据

permgen去除原因:永久代中的元数据可能会随着每一次Full GC发生而进行移动。并且为永久代设置空间大小也是很难确定的,因为这其中有很多影响因素。

数据类型分为两种

  概念 内存 使用 局部 全局
基础数据类型(char,int,boolean等) 指向具体数值 直接分配内存 不能为null 值和变量名都在栈 堆里
引用数据类型(类,接口,数组) 指向地址 没有内存,只有地址 可以为null 实例在堆,地址在栈 堆里

回收机制

可回收对象的判定方法

引用计数算法

每当有地方引用,计数器加一,引用失效减一,算法简单,但是会出现两个对象相互持有。如图(其他博客那拿的)。

可达性分析算法

通过一些可以被当做GC Roots的对象,向下搜索,走过的路径称为引用链。当对象没有和引用链相连时,则说明可以回收。

                                             

可以当做GC Roots的对象

1.本地方法区JNI的引用对象;

2.方法区的常量对象,目前我只知道final这种形式的常量对象,还有别的可以告诉我一下;

3.方法区类静态属性的引用;

4.java虚拟栈的局部变量引用;

注:可达性分析算法中,不可达对象并非“非死不可”,有一个可以救赎的办法,就是复写finalize()方法。但是!!

复写这个方法,不保证会执行完里面的代码。经过事实证明,执行完成率低,调用代价带,极为不推荐复写!!

按照一个博主所说,这个方法是为了让C/C++程序员尽快适应JAVA所做出的妥协。

不太想详细讲的算法就直接把我做的PPT贴出来了。

所有算法都用到了标记清除算法,着重讲一下现在用的最多的分代回收算法

首先分代回收算法不是一个单独使用的算法,需要其他的算法配合使用。

                 

 Eden(伊甸园区):新生代区,用来分配创建新的对象,被划分为多个县城本地分配的缓冲区,划分后,JVM在对应线程缓冲区直接分配可以避免同步操作。

Survivor(存活区):有2个存活区称为to区和from区。To区开始为空,开始GC后,Eden与From区把有用对象放进To区。然后会有一个头部计数加一,等15次之后会进入老年区。To区与From区总会任意时刻总有一个空的。

Old Generation(老年区):里面对象是垃圾概率很小,所以发生GC频率会很低。

Minor GC:用于清理年轻态区域 Major

GC:清理老年代区域

Full GC:(完全GC)清理的是整个堆

GC发生时会有一个全线暂时停止操作,垃圾收集过程中,需要暂停应用所有线程,不过时间非常短。

OOM原因

Heap(堆)是由程序员自己来控制的,OOM是因为android系统对Dalvik虚拟机的heap大小做了硬性限制,当JAVA进程申请空间超过这个数值时就会OOM(这个阈值因机型而异)。

程序发生OOM并不表示RAM不足,RAM充足情况也会OOM。

RAM目的是为了更多应用能常驻在其中,这样程序启动不必每次都加载到内存,这样启动应用速度会更快。当RAM真的不足时,memory killer会杀死一些优先度低的进程。

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章