JVM第二、三章笔记

第二章 Java内存区域与内存溢出异常

运行时数据区域:程序计数器、虚拟机栈、本地方法栈、堆、方法区;

程序计数器 归属:线程私有;内容:正在执行Java方法,则指向当前线程正在执行的字节码地址;本地方法,则程序计数器为空;异常:唯一无OutOfMemoryError

虚拟机栈 归属:线程私有;内容:局部变量表(含有基本数据类型、引用类型、returnAddress类型;该部分的空间大小在编译期完全确定且不在运行期变化)、操作栈、动态连接、方法出口等信息。每个方法的调用都对应着一个栈帧入栈和出栈的过程;异常:StackOverflowError(栈的请求深度大于栈的深度)和OutOfMemoryError;

本地方法栈 类似虚拟机方法栈,只是本地方法栈为native方法提供服务。

Java堆:归属:线程共享;内容:存放实例对象(物理空间不连续的存储方式);异常:OutOfMemoryError

方法区 归属:线程共享;内容:已被加载的类信息、常量(字面量和符号引用,处于方法区中的常量池)、静态变量等;异常:OutOfMemoryError;

直接内存 归宿:不是虚拟机运行内存的一部分;例如,NIO类直接对Native堆内存进行操作;异常:OutOfMemoryError;

 

对象访问方式

使用句柄:java栈中的引用稳定,但速度和内存开销大。

使用直接指针:java栈中的引用不稳定,但速度和内存开销小。(Hopspot使用该方式)

 

实战OutOfMemoryError

可以通过JVM参数设置堆/非堆大小

-vmargs -Xms128M -Xmx512M -XX:PermSize=64M -XX:MaxPermSize=128M

-vmargs 说明后面是VM的参数,所以后面的其实都是JVM的参数了

-Xms128m JVM初始分配的堆内存

-Xmx512m JVM最大允许分配的堆内存,按需分配

-XX:PermSize=64M JVM初始分配的非堆内存

-XX:MaxPermSize=128M JVM最大允许分配的非堆内存,按需分配

-Xss128k 设置栈(不区分虚拟机栈和本地方法栈)的内存大小,每个线程私有改内存空间。

-XX:MaxDirectMemorySize 指定直接内存空间的大小

 

第三章 垃圾收集器与内存分配策略

如何判断对象已死

引用计数法:有一个地方引用加1,当引用失效时减1,但是该方法不能解决相互循环引用。

根搜索算法:“GC Root“为起点,类似树形结构向下搜索,如果没有任何链能到达一个对象,则称该对象为对象不可达状态(unreachable)。

“GC Root“可以是栈中引用的对象、类静态属性引用的对象、常量引用对象、JNI引用对象;

引用分类:强/软/弱/虚引用;强:不会被GC;软:内存不够时GC;弱:下次GC;虚:GC并给通知。

对象复活的案例:finalize()方法放入低优先级的队列中只能执行一次,不建议使用。

方法区中的GC:收集废弃常量(无任何引用时)和类卸载(无实例、无类加载器、没有应用该类的Class对象)

 

3中垃圾收集算法:

标记-清除算法:先“标记“后”清楚“,缺点:效率不高,清除后空间不连续。

复制算法:将内存分为一块Eden和两块Survivor空间,每次只使用一块Eden和一块Survivor,将存活的对象拷贝到没有用的那块Survivor空间(若空间不够自动扩展)。效率高但是牺牲了内存空间。

标记-整理算法:让所有存活的对象向一段移动,并清理到边界外的对象(清理后无碎片)。

当前虚拟机采用“分代收集“的方式,将java堆分为老年代和新年代。老年代需要清理的对象少,可以采用算法1和3(一般用3)。青年代需要清理的对象多,可以采用复制算法。

 

垃圾收集器(分为老年代垃圾收集器和新年代垃圾收集器)

新年代

Serial

单线程收集器,在收集垃圾的时候会”Stop The World”,简单而停顿时间长;

ParNew

Serial收集器的多线程版本,仍然需要”Stop The World”;

ParallelScavenge

类似ParNew收集器,但是关注停顿时间和吞吐量(运行客户代码时间/(运行客户代码时间+垃圾收集时间));不能与CMS收集器搭配

 

老年代

SerialOld

两大用途:与ParallelScavenge收集器搭配使用;作为CMS收集器后备方案。

parallelOld

SerialOld的多线程版本

CMS

并发收集器,使用标记-清除算法;

流程:初始标记-并发标记-初始清理-并发清理;

缺点:占用线程,堆CPU资源敏感;无法处理浮动垃圾;内存空间碎片。

G1收集器

 

对象优先在新生代Eden区:新生代采用复制清理算法

大对象直接进入老年代:为了避免在survivor区之间发生大量数据拷贝而影响效率。

长期存活对象进入老年代:每次Minor GC后存活对象增长1岁,到一定年龄后进入老年代。

动态对象年龄判定

空间分配担保:Minor GC前无法知道有多少对象存活,为了防止Survivor空间不足故用老年代担保(通过参数设置是否担保)。Minor GC前,用上次进老年代的对象容量作为经验值,决定是直接FULL GC还是尝试Minor GC.

 

posted @ 2019-06-30 22:20  由走啦啦啦  阅读(104)  评论(0编辑  收藏  举报