JVM知识总结

Java的运行时内存分布图:

线程隔离:VM Stacks(其中有Stack Frame, Stack Frame中有局部变量表,局部变量表中存有对象引用)、Native Method Stack、PC Counter

线程共享:方法区(Method Area)(包括class代码、字符串常量等)、堆(Heap)

http://blog.jamesdbloom.com/JVMInternals.html

 

HotSpot中的垃圾收集器

,其中可以选择各种回收算法:

说道垃圾收集,判断对象是否存活,包括引用计数(因没法解决循环引用问题而被抛弃,但仍然在一些网页应用语言中使用),一种是GC Roots(这包括VM Staks中的引用,类的静态属性引用的对象、方法区的常量引用、Native Method Stack中JNI方法引用的对象)引用链。  全局性引用、执行上下文。

图片请参考https://blogs.oracle.com/jonthecollector/entry/our_collectors

早期的有停顿,减少停顿,减少对用户影响成为目标。

下列的收集器都使用了SafePoint,一种GC Roots方法中借助OopMap完成收集GC Roots引用信息的快照时间点,有抢先式中断(被动式的,指的是gc线程去控制)和主动式中断(GC指定标志位让用户线程去轮询)。

Serial收集器:有停顿,对于运行在Client模式下虚拟机是好的选择。新生代采取复制算法(内存分配不必1:1,因为有老生代的担保)、老生代采取mark-compact算法(让所有存活对象都向一端移动,而后清除另一端)

ParNew收集器:使用多线程收集,配置参数包括控制参数、收集算法、Stop the world、对象分配规则、回收策略;是Serial的多线程版本,默认开启与CPU相同线程数(-XX:ParallelGCThreads)。是很多运行在Server模式下的虚拟机中的首选新生代收集器(因为可以与CMS配合使用)。是使用了-XX:+UseConcMarkSweepGC选项后的默认新生代收集器,也可以用-XX:+UseParNewGC选项指定。

Parallel Scavenge收集器:新生代收集器,目标是达到一个可控的吞吐量,高吞吐量达到的目标是尽快完成程序的运算任务,适合后台运算需求型。用这两个参数来精确控制,-XX:MaxGCPauseMillis, -XX:GCTimeRatio,GC停顿时间要小可能是以牺牲吞吐量和新生代空间来换取的。还有-XX:UseAdaptiveSizePolicy用于自适应调整新生代大小、Eden与Survivor比例、晋升老生代年龄等细节参数(http://docs.oracle.com/javase/1.5.0/docs/guide/vm/gc-ergonomics.html)。不过无法和CMS一起工作。-XX:+UseParallelGC开启的是PS+Serial Old(PS MarkSweep)组合。

Serial Old收集器:是Serial的老年代版本,使用Mark-Compact算法。主要也还是client模式下使用,或者作为cms的后备,或者在jdk1.5及以前与Parallel Scavenge一起配合使用。

Parallel Old收集器:是Parallel Scavenge的老年代版本,使用多线程和Mark-Compact算法。从jdk1.6开始提供,在这之前新生代Parallel Scavenge只能尴尬的选用Serial Old作为老年代配合)。要开启的话得用UseParallelOldGC,在注重吞吐量和CPU敏感的情形下较适用。

CMS(Concurrent Mark Sweep)收集器:以获得最短响应时间为目标的收集器,是基于mark-sweep算法。CMS initial mark(GC Roots直接的,需要stop the world,但时间很短),CMS concurrent mark(GC Roots引用链,与与用户线程并发)、CMS remark(解决并发过程中可能发生的变化,stop the world,时间也不会很长)、CMS concurrent sweep(并发)。优点是低停顿,缺点是对cpu敏感、可能触发Concurrent Mode Failure从而导致一次Full GC产生(这是老年代中,cms current sweep期间程序继续运行会产生新的垃圾、产生的垃圾充满了原本给这期间用户线程运行所预留的空间,这样内存不够,会让jvm临时启用serial old收集器来重新进行老年代的垃圾手机,停顿时间很长),还有即内存碎片(这通过在碎片太多快Full GC时开启合并整理来改善,内存整理过程是无法并发的,会增加停顿时间)。开启时使用UseConcMarkSweepGC开启的是ParNew+CMS+Serial Old组合。

G1(Garbage First)收集器:在jdk7u4中成为正式。把java内存堆分为多个region,避免进行全区域的垃圾收集而是维护一个优先列表。Initial Marking、Concurrent Marking、Final Marking、Live Data Counting and Evacuation(筛选回收)。最后筛选回收阶段先对各region的回收价值和成本进行排序,而后根据用户期望的GC停顿时间来指定回收计划。

 

对于老年代区域对新生代区域的变量引用,使用card marking(卡片标记),只扫描老年代区域中“Dirty”的部分。

内存分配

对象优先在新生代Eden区分配:内存不够时会有Minor GC(很频繁,速度很快)使用copying算法,copy到survivor区。

大对象直接进老年代:(很长的字符串和数组)

长期存活的对象将进入老年代:对象在Survivor中每熬过一次Minor GC就变“老”一点。

动态对象年龄判断。

空间分配担保:如果不够时是会触发Full GC。老年代的连续空间大于新生代对象总大小或者历次晋升的平均大小就会Minor GC,否则Full GC

Young(Eden+2*Survior) /Tenured /Perm(method area)

 

http://www.cubrid.org/blog/dev-platform/understanding-java-garbage-collection/

在HotSpot VM中,为了加快MemoryAllocation,使用了两个技术:

    bump-the-pointer:使用指针跟踪最后一次内存分配的对象,这样当新的内存分配请求到来时,检查剩下是否够即可。

    TLABs(Thread-Local Allocation Buffers):this allows each thread to hava a small portion of its Eden space ths corresponds to its own share.

 

与程序编译运行时的概念,main memory/ working memory的区别与联系:

两个层面的,若要对应。main memory------堆中的对象实例数据部分;working memory------VM Stacks的部分区域

从硬件上,有可能main memory是对应物理内存,而working memory对应寄存器和cache中。

工具

jmap:

    https://thenonsensetechlogs.wordpress.com/2014/04/09/error-attaching-to-process-sun-jvm-hotspot-debugger-debuggerexception-cant-attach-to-the-process-solved/

posted on 2015-07-09 11:00  majia1949  阅读(122)  评论(0编辑  收藏  举报

导航