方法区(常量池...) 永久代 Class对象在方法区
堆---新生代(eden ,from survivor,to survivor),老年代(old)
虚拟机栈
程序计数器 线程独占
本地方法栈
对象的创建:内存分配:1.指针碰撞,顺序整块分配。2.空闲列表,找到足够大小的空间分配。
对象头【自身运行时数据(mark word 、hashcode、gc年龄、锁标志。。。),类型指针(对象指向其类元数据,可确 定类的大小,数组不行,不一定所有对象都有查找元数据信息不一定要根据对象本身即通过句柄)】
对象 实例数据
对齐填充
对象索引:1.句柄(不需要修改reference)。2.直接指针(速度快,节省一次指针开销)
GC:1.引用计数器法
2.可达性分析算法(GC Roots)
虚拟机栈中引用的对象、方法区中静态属性引用的对象、方法区中常量引用的对象、本地方法栈中引用的对象JNI。
引用:强(不会被回收)、软(有用但非必须,在内存溢出之前会进行二次回收)、弱(非必须,能生存到下次gc之前)、 、、、虚 (回收前给个提示)。
一个对象被回收至少经历两次标记,第一次可达性分析后进行筛选,筛选的条件是是否有必要执行finalize()方法,没有重写该方法或者已经被调用一次视为没必要执行。
判定一个类是否可回收:1.所以实例被回收2.加载该类的ClassLoader被回收3.该类的Class对象没有在任何地方引用
垃圾回收算法:
1.标记-清除(效率不高,产生大量内存碎片,遇到大对象容易导致GC)
2.复制算法(内存分为两块,存活对象之间复制到另外一半,然后清理,内存开销浪费,运行高效,新生代算法8:1:1)
3.标记-整理(存活率高的情况下,效率低下。老年代算法) !!分配担保机制,新生代空间不足直接进入老年代
安全点:gc发生在该时间点,hotspot 通过OopMap枚举根节点
gc发生时,所有线程停顿,1.抢先式中断(先中断,不在安全点再恢复运行) 2.主动式中断(设置一个标记,轮询,为真就挂起)
线程处于sleep或者blocked状态不会响应中断,这个时候需要用到 安全区域
垃圾收集器:共七中垃圾收集器,分别是serial、parnew、parallel scavenge和cms、serial old、 parallel old、G1;其中serial、parnew、parallel scavenge用于年轻代,cms、serial old、 parallel old用于年老代,g1用于年轻代和年老代。所有收集器都存在stop the world,不过在java发展中 一直在优化停顿时间。
年轻代:
Serial:适用于年轻代垃圾回收,复制算法,jdk1.3之前 推荐用于客户端模式(Client)下的虚拟机,属于单线程,无对stop the world优化,属于最老的年轻代垃圾收集器产品; 单线程
ParNew:适用于年轻代垃圾回收,复制算法,jdk1.3发布,推荐用于服务端模式(Server)下的虚拟机,属于多线程,无对stop the world优化,其实就是Serial的多线程版本;是服务端开发的首先; 并行
Parallel Scavenge:适用于年轻代垃圾回收,复制算法,jdk1.4发布,属于多线程,无对stop the world优化,它是一个可以控制吞吐量的收集器,拥有自适应调节策略;需要注意一点的是,gc停顿时间缩短是牺牲吞吐量和新生代空间来换取的。 并行
stop The World:gc时 需要停止所有线程进行垃圾回收;
吞吐量=运行用户代码时间/(运行用户代码时间+垃圾收集时间)
自适应调节策略:虚拟机会根据当前系统的运行情况收集性能监控信息,动态调整参数以提高最合适的停顿时间或最大吞吐量。
年老代
Serial old :适用于年老代垃圾回收,标记-整理算法,jdk1.5之前,主要用于client下的虚拟机,如果用在server模式下主要有俩个作用:一是jdk1.5以及之前用于与Parallel Scavenger搭配使用,二就是为cms提供后备预案,属于单线程,无stop the world优化。 单线程
Parallel Old:适用于年老代垃圾回收,标记-整理算法,jdk1.6发布,属于多线程,注重于吞吐量控制,是为了Parallel Scavenge定制的; 并行
CMS: 适用于年老代垃圾回收,标记-清除算法,jdk1.5发布,推荐server模式下,属于多线程,对stop the world有优化,CMS是一种以获取最短回收停顿时间为目标的收集器,也就是优化服务器响应速度。CMS分为4步:其中 初始化标记,重新标记 stop the world
初始标记:仅仅只是标记GcRoots可以直接关联的对象; 单线程
并发标记:进行gcroots tracing(也就是 引用链搜索);优化成并发 并发
重新标记:修正并发标记因用户程序继续运行而导致标记产生变动那一部分对象的标记记录。 并行
并发清除:并发清理标记的对象内存。 并发
重置线程 并行
CMS缺点:
CMS对cpu资源非常敏感,默认启动的回收线程数是(cpu数量+3)/4;垃圾回收线程数量不少于25%的cpu资源,当cpu越大,线程数/cpu总量 越小;但是当cpu小于4个时 显得就不怎么合适了;无法处理浮动垃圾,需要等下一次gc才能处理;并且还需要预留一部分空间提供并发收集时的用户程序运作使用,即启动阈值(-XX:CMSInitiatingOccupancyFraction 阈值百分比);要是CMS运行期间预留的空间不满足程序需要,就会出现一次“Concurrent Mode Failure”失败,这是虚拟机启动后备预案:临时启用Serial Old,这样一来停顿时间就很长了,所以-XX:CMSInitiatingOccupancyFraction 设置太高容易导致大量“Concurrent Mode Failure”失败,性能反而降低。 由于用的是标记-清除算法,所以会出现内存碎片;CMS提供-XX:UseCMSCompactAtFullCollection开关参数(默认为开),用于CMS收集器要进行FullGC时进行内存碎片合并整理,-XX:CMSFullGCsBeforeCompaction 用来设置执行多少次不压缩Full GC后跟着来一次带压缩的(默认为0,表示每次进入Full GC都进行碎片压缩)。
年轻代+年老代
G1:jdk1.7发布,整体看是“标记-整理算法”,从局部(俩个Region之间)上来看是基金“复制”算法实现,也就是说没有内存碎片;
初始标记:仅仅只是标记GcRoots可以直接关联的对象; 单线程
并发标记:进行gcroots tracing(也就是 引用链搜索); 并发
最终标记:修正并发标记因用户程序继续运行而导致标记产生变动那一部分对象的标记记录。 并行
筛选回收:根据各个Region回收价值成本排序,根据用户qi'w期望的GC时间来zhi'制定回收计划 并行
如果应用追求低停顿,那G1现在可以作为一个尝试的选择,如果应该追求吞吐量,G1并不会带来什么特别的好处!!!
第二部分:第四章
jdk的命令行工具简单总结介绍
jps(Java Process State): 获取虚拟机进程 vmid; jps options hostid
jps -v :显示虚拟机对应启动的参数
-q 只输出LVMID
-m 输出vm进程启动时传递给主类main()函数的参数
-l 输出主类全名,如果进程执行的是Jar包,输出Jar的路径 时间间隔 次数
jstat:虚拟机监控工具,jstat -gccause vmid:输出已使用空间占各自总空间的百分比; jstat options vmid interval count
[protocol:][//]lvmid[@hostname[:port]/servername]
jstat -gc 2764 250 20 每隔250ms查询一次进程2764的gc情况,一共20次
-class 监视类装载、卸载数量、总空间以及类装载耗时
-gc 监视Java堆状况,eden、survivor、老年代、永久代等容量,已用空间、GC时间合计
-gccapacity 与-gc基本相同,但输出主要关注Java堆各个区域使用到的最大、最小空间
-gcutil 与-gc基本相同 输出已使用空间百分比
-gccause 与-gcutil一样 但是额外输出导致上一次gc原因
-gcnew 监视新生代
-gcnewcapacity 与-gcnew基本相同,关注使用到的最大最小空间
-gcold
-gcoldcapacity
-gcpercapacity 永久代
-compiler 输出JIT编译器编译过的方法、耗时等信息
-printcompilation 输出已经被JIT编译的方法
jinfo:获取虚拟机参数值和动态修改部分运行期可改的参数。jinfo [option] pid例如:jinfo -flag PermSize vmid;显示vid对应的虚拟机的方法区大小;jinfo -flag +/- name ,添加或删除name属性;
jinfo -flag name=value
jinfo -sysprops
java -XX:+PrintFlagsFinal 查看默认参数
jmap:java内存影像工具,
jmap -heap vmid:显示堆的详细信息,如参数配置,分代状况;
-histo vmid:显示堆中对象统计信息,包括类,实例数量,合计容量。
-dump 生成Java堆转储快照格式为 -dump:[live,]format=b,file=<filename> live说明是否只dump存活对象
-finalizerinfo 显示在F-Queue中等待Finalizer线程zhi 执行finalize方法的对象
-permstat 以ClassLoader为统计口径显示永久代内存状态
-F 强制生成dump快照
jhat:虚拟机堆转储快照分析工具; localhost:7000
jstack:java堆栈跟踪工具; 生成线程快照:方法堆栈的集合
-F 强制输出线程堆栈
-l 除了堆栈以外还输出关于锁的附加信息
-m 如果调用到本地方法还会显示C/C++的dui'堆栈
HSDIS:JIT生成代码反汇编
jdk的可视化工具:jConsole和visualVm;其中VisualVM有个BTrace插件值得注意。
BTrace 动态日志跟踪:可以打印调用堆栈、参数、返回值、性能监视、定位连接泄漏、内存泄漏、解决多线程竞争问题。如生产上遇到问题时需要方法输入参数和返回输出参数,但开发时没有日记记录,平常做法就是补充上日志,然后在重现上线。而BTrace可以在不停止jvm的情况下动态调试代码。(ps:BTrace后续深入研究)
推荐一篇文章:http://huanghaifeng1990.iteye.com/blog/2121419
第二部分:第五章
简单总结:
一、jvm调优思路:
第一步:jps 获取jvm id;
第二步:获取jvm垃圾收集器种类
第三步:查看gc次数和时间,分析原因来优化
gc次数频繁:①、内存回收率低导致短时间内回收次数多;②、内存大小太小;
gc时间长:①、内存过大;②、内存扩展导致时间长(固定内存大小)
选择适合的收集器也可大幅度优化jvm。
二、优化思路注意点:
1、64位jdk的性能测试结果普遍低于32位jdk;
2、64位jdk由于指针膨胀和数据类型对齐补白导致消耗的内存比32位大;
3、使用nio时,堆外内存(direct memory)不足导致内存溢出。