一。内存区域与内存溢出异常

1. Java虚拟机的运行时数据区:

-----------------------------------

  运行时区域

方法区  虚拟机栈 本地方法栈

堆    程序计数器

————————————————

执行引擎  -->  本地库接口   --> 本地方法库 (线程共享)

2. 程序计数器PC

控制字节码解释器,执行字节码;由于Java的多线程是通过线程轮流分配处理器执行时间实现的,因此每个线程有一个程序计数器;

如果是Java方法,则记录的是字节码的地址;如果是Native方法,则为空;

3. Java虚拟机栈

内存分为堆和栈,栈就是指的虚拟机栈;

每个方法被调用时创建一个栈帧,存放局部变量、操作栈、方法出口;

局部变量表里存放了基本数据类型、对象引用和返回地址;

如果线程申请的栈深度超出了允许的深度,抛出StackOverflowError,如果虚拟机栈因冬天扩展无法申请到足够的内存,抛出outofmemoryerror.

4. 本地方法栈

和Java虚拟机栈类似,为调用Native方法服务;

5. 堆

Java的堆是被所有线程共享的一块内存区域,虚拟机启动时创建;其目的是存放对象实例;

堆是垃圾收集器的主要管理区域;现在的算法是分代回收算法,分为:新生代和老生代;再细分:Eden, From survivor, to survivor空间;

从内存分配来看,Java堆中还可分成多个线程私有的分配缓冲区;

物理不连续,逻辑连续;

6. 方法区

永久区,存放常量池和类型的卸载;线程共享;

7. 运行时常量池:在方法区;动态性;

8. 直接内存:采用Native库分配堆外内存,存储在Java堆里的DirectByteBuffer对象作为引用;避免在Native堆和Java堆中交换数据

二。对象访问及溢出

object obj = new object()

obj 本地变量区;new object 在Java堆,Java堆中还有类型数据的地址信息(方法、父类、接口等);

有两种实现方式,采用句柄或者直接指针的方式进行访问;

句柄:引用 (本地变量表) -> Java堆的句柄池 ->Java堆的实例池 和 方法区的数据

指针:引用->Java堆的对象实例数据 (含有方法的指针) ->方法区的类型数据

-Xmx -Xms 堆的最大和最小 -Xoss 栈的大小

反复调用函数是栈溢出;反复申请空间是堆溢出;不断在常量池添加常量,导致常量池溢出;不断注册新的方法,导致方法区溢出;使用Unsafe分配本地内存,导致溢出;

三。垃圾回收及内存分配

1. 判断对象死亡的方法:

引用计数方法:无法解决互相引用的情况

根搜索算法(Java C# Lisp中都用的这个):作为跟的对象:虚拟机栈里的对象,方法去中类静态属性对象,常量引用对象,本地方法JNI的引用的对象;

如果一个对象已被执行finalize 或者 没有重载,则第一次标记;如果一个对象重写了必须执行的finalize()函数,则执行,如果执行过程中重新建立联系,则移除Fqueue,否则进行第二次标记,执行释放空间;但finalize方法只被执行一次!

可以调用两次System.gc;并在finalize中使某个引用指向自己,造成一次无法释放,一次释放的假象;

2. 方法区

废弃常量和死亡对象差不多;

废弃的类需要判断:类的所有实例都被回收,java堆中不存在实例;c该类的classloader已被回收;class没有被引用,也不能通过反射得到该类;

使用反射、动态代理等场景,需要永生代回收;

标记-清除算法:最基础的,标记需要释放的,逐个释放

复制算法:内存分成两块,将需要释放的一块的活的对象复制到另一块,直接释放一整块内存

标记整理算法:先标记,再移动内存

分代收集算法:将内存分为新生代和老生代,新生代,存活较少,采用复制算法;老生代采用标记-清除或标记-整理算法;

三。垃圾收集器

Serial 收集器:单线程工作,收集工作进行时,停止其他所有的工作线程(Client模式下新生代);(复制算法)

ParNew 收集器:多线程工作(server模式下新生代,多核)

Parallel Scavenge 收集器:新生代,多线程收集器(目标在与达到最大吞吐量,吞吐量=(用户代码时间)/总时间),复制算法

Serial Old 收集器:老年代收集器,标记整理算法;

Paralle Old: 老年代,多线程,标记整理

CMS (concurrent mark sweep): 最短时间为目标;标记清除算法;

  特点:1.与用户线程并行;2.对CPU资源敏感;3.无法处理浮动垃圾(标记之后用户线程产生的垃圾);4. 基于标记-清除,产生内存碎片,不利于大内存的分配;

G1 (Garbage First): 标记-整理算法,无碎片;非常精确的控制停顿;

四。内存分配策略

1. 对象优先存在新生代;2.大对象直接进入老生代;3.长期存活按年限进入老生代(躲过一次minorGC长一岁);

minorGC是将新生代的对象分配到老生代;

五。工具

1. 常用的数据:运行日志,异常堆栈,GC日志,线程快照,堆转存快照;

2. sun JDK 1.6 监控和故障处理的工具

jps  JVM process status tool,  查询虚拟机进程,显示主类;

jstat  Jvm statistics monitoring tool, 显示虚拟机的类装在,内存,垃圾收集,JIT编译等数据;

jinfo  实时配置和查看虚拟机的参数

jmap  java内存映像工具,用于生产堆转储快照;还可查询finalize执行队列;Java堆、和永久代的详细信息;

jhat  java虚拟机转储快照分析工具

jstack  堆栈分析工具

3. 可视化

JConsole : Java监视与管理控制台: Eden 和Survivor默认比8:1

VisualVM + BTrace分析日志VisualVM插件

posted on 2014-09-11 22:50  zhang123shuo  阅读(163)  评论(0编辑  收藏  举报