标签:
一):运行数据区
1:程序计数器(Program Counter Register),也称"PC寄存器"
A:用来指示需要执行哪条指令的。(在汇编语言中,CPU在得到指令之后,程序计数器便自动加1或者根据 转移指针得到下一条指令的地址,如此循环,直至执行完所有的指令。)
B:由于在JVM中,多线程是通过线程轮流切换来获得CPU执行时间的。每个线程都有独立的程序计数器,属 于私有的。
C:如果线程执行的是java方法,这个计数器记录的是正在执行的虚拟机字节码指令地址;如果正在执行的是 Native方法,则程序计数器中的值是undefined。
D: 由于程序计数器中存储的数据所占空间的大小不会随程序的执行而发生改变,因此,对于程序计数器是不会 发生内存溢出现象(OutOfMemory)的。
2:虚拟机栈(VM Stack),也称 Java栈
A:每个方法执行都会创建一个栈帧(Stack Frame),用于存储局部变量表,操作数栈,常量引用,动态链接, 方法出口等其他附加信息;-Xss参数设定。
B:对于基本数据类型的变量,则直接存储它的值,对于引用类型的变量,则存的是指向对象的引用。局部变量 表的大小在编译器就可以确定其大小了,因此在程序执行期间局部变量表的大小是不会改变的。
C:如果线程请求大于虚拟机允许的深度,将抛出StackOverflowError;如果虚拟机栈可以动态扩展(也允许 固定长度),扩展时内存不够,就抛出OutOfMemoryError。
3:本地方法栈(Native Method Stack)
A:与虚拟机栈作用相似,区别就是它为Native方法服务的;
B:有的虚拟机(如Sun HotSpot)把本地方法栈和虚拟机栈合二为一;
4:堆(Heap),即java堆
A:Java中的堆是用来存储对象本身的以及数组(当然,数组引用是存放在Java栈中的);
B:Java堆是垃圾收集器管理的主要区域,Java堆在虚拟机启动时创建,被所有线程共享;
C:Java堆里面分为:新生代和老生代;
D:在实现时,既可以是固定大小又可以是可扩展的(通过-Xmx和-Xms控制,设置一样就不能自动扩展), 如 果堆内存不够将会抛出OutOfMemoryError;
5:方法区(Method Area)
A:在方法区中,存储了每个类的信息(包括类的名称、方法信息、字段信息)、静态变量、常量以及编译 器编译后的代码等。
B:别名 Non-Heap ,非堆;目的应该是区别java堆;设置-XX:PermSize和-XX:MaxPermSize限制方法区 大小;
C:HotSpot上很多人习惯把方法区看做“永久代”,但是本质上两者并不等价!
HotSpot是使用永久代来实现方法区的,这样GC就可以像管理Java堆一样地管理方法区了,省去了为 方法区编写内存管理的代码。但其他虚拟机(JRockit,J9等)来说是不存在永久代的;原则上如何实现方 法区,不受虚拟机规范约束;对于HotSpot现在也有放弃永久代并逐步改为Native Memory来实现方 法区的规划了;jdk1.7的HotSpot中已经把原本放在永久代的字符串常量池移除;
D:方法区无法满足内存分配时,将抛出OutOfMemoryError;
E:运行时常量池时方法区的一部分;
6:直接内存,受物理内存大小限制;
1:程序计数器、虚拟机栈、本地方法栈都是随着线程而生,随线程而消亡;需要回收的是堆和方法区;
2:对象已死吗?对象已经被回收了吗?
1) 引用计数法:给对象添加一个引用计数器,每当对象有个引用,计数器就加1,引用失效就减1,当引用计 数器为0时,该对象就不可能再被使用了(回收)(很多人的答an)。
但是,至少主流的java虚拟机没有使用这种算法来管理内存,主要原因是它很难解决对象之间的循环引用。
2)可达性分析算法:主流都是通这个算法来判断对象是否存活。
这个算法基本思想就是通过一些列的‘GC Roots‘的对象作为起始点,从这些节点开始往下搜索,搜索所走过 的路径成为‘引用链‘,当一个对象到GC Roots没有任何引用链死,就是从GC Roots到这个对象不可达。则证 明这个对象不可用,这些对象将被判定可回收。
但这些对象不是‘非死不可‘(缓刑阶段),要宣告一个对象死亡,至少要经历两次标记。GC Roots不可达将会 进行第一次标记且进行一次筛选,筛选的条件就是此对象有没有必要执行finalize()方法,当对象没有覆盖 finalize()或finalize()被虚拟机调用过,这两种情况虚拟机视为"没有必要执行"。此外就是有必要执行,那 么这个对象就是会被放入F-Queue的队列中,finalize()方法是对象逃脱死亡的最后一次机会(把对象赋值给 某个变量);稍后GC对F-Queue中的对象进行小规模的第二次标记,被两次标记对象真的要被回收了。
3)回收方法区:
A:java虚拟机规范可以不要求虚拟机在方法区实现垃圾收集,方法区(永久代)垃圾收集效率比较低。
B:永久代垃圾收集分为两部分:废弃常量和无用的类。
回收废弃常量和回收java堆中对象非常类似,但常量没有其他地方引用就会被移除常量池(回收),方法区 中的类(接口)字段等符号引用也是如此。
满足以下3个条件才算是‘无用的类‘:(是否被回收,虚拟机提供了一些设置参数)
1:该类的所用实例都已经被回收
2:加载该类的ClassLoader已经被回收
3:该类对应的java.lang.Class对象没有任何地方被引用,无法通过发射访问该类的方法
4)垃圾收集算法:
A:标记-清除算法:分为标记和清除两个阶段。有两个问题1:效率不高 2:会产生大量不连续的内存碎片。
B:复制算法:运行高效。
C:标记-整理算法:老年代一般使用这种算法 。
D:分代收集算法:
当前商业虚拟机的垃圾收集都采用分代收集;
根据对象存活周期的不同把内存划分为几块;
一般是把java堆分为新生代和老年代,根据各个年代特点采用不同算法,
在新生代,每次垃圾收集就有大量对象死去,所以采用复制算法;
在老年代,对象存活率较高,就采用标记-清除或标记-整理算法;
5)垃圾收集器:如果说垃圾收集算法是内存回收的方法论,那么垃圾收集器就是具体实现;有好7种。
A:Serial收集器:单线程的。发展历史最悠久的收集器。简单高效,jdk1.3之前 新生代的唯一选择。
B:ParNew收集器:Serial的多线程版;是运行在Service模式下的虚拟机中首先的新生代收集器。jdk1.3
C:Parallel Scavenge收集器:使用复制算法的新生代收集器,又是并行的多线程收集器;jdk1.4。
D:Serial Old收集器:是Serial送机器的老年代版本,单线程,使用标记-整理算法,主要意义在于给 Client模式下的虚拟机使用;jdk1.5
E:Parallel Old收集器:Parallel Scavenge收集器老年代版本,多线程,采用标记-整理的算法;jdk1.6
F:CMS收集器:是以获取最短回收停顿时间为目标的收集器,基于标记-清除算法。并发收集低停顿.jdk1.5
J:G1收集器:jdk1.7中,面向服务端应用的垃圾收集器,未来可能替换掉CMS收集器;
特点:1并行与并发;2分代收集;3空间整合;4可预测的停顿;
运作步骤:1:初始标记;2:并发标记;3:最终标记;4:筛选回收;
6)内存分配与回收策略:
A .对象优先在Eden上分配:
大多数情况下,对象在新生代Eden上分配,但Eden上没有空间了,虚拟机会发起一次Minor GC(发生在新 生代垃圾收集动作,比较频繁,一般回收速度快);老年代GC(Major GC 或Full GC),发生在老年代的 GC,出现了Major GC ,经常会伴随至少一的 Minor GC(但非绝对);
B.大对象直接进入老年代:大对象就是需要大量连续内存空间的java对象,最典型的就是较长的字符串以及数组
C.长期存活的对象将进入老年代:
有个对象年龄计算器,每熬过1次Minor GC 年龄就加1岁,当年龄到达默认值(15岁)就会晋升到老年代中, 这个年龄阀值可以通过设置-XX:MaxTenuringThreshold;
写博客有点累,未完待续》。。
标签:
原文地址:http://my.oschina.net/dyyweb/blog/513800