jvm gc相关

jdk在运行是有个计数器,可以理解为当前代码段的行号
每个独立的线程都有一个独立的计数器,以便在切换后可以保持原有的现场
计数器是不会出现oom现象的

虚拟机栈也是线程私有的,每个方法都会创建一个栈帧,每个方法执行完成就是一个入栈出栈的过程
如果栈深度超过允许深度,就会抛出stackoverflowError
如果jvm动态扩展,但是内存超了,就会抛出outofmemoryError

本地方法栈就是执行一个native的方法,有的是合二为一的

java的堆是被所有内存所共享的一块区域,
基本所有的对象的空间分配都是在这块空间上面(随着JIT的成熟,慢慢分配在堆上变得不那么绝对了)
GC主要发生在堆上面,可以使用Xmx Xms来控制堆的伸缩

方法区,经常和永久代做关联

运行时常量池,例如String.intern就是放在这个里面的
-XX:+PrintGCDetails


当new一个对象的时候就是在堆上分配一块空间
指针碰撞(左右两块空间):当使用Serial,ParNew这种带compace的GC的时候
空闲列表(维护一个空闲列表):当使用CMS这种的时候,

多线程分配空间的时候有两种
同步操作(CAS)
每个线程都有个自己的TLAB空间,可以使用 UseTLAB来指定空间

内存分配的时候将空间都改为0

对象的内存空间
头:HashCode,GC分代年龄,锁状态,MarkWord; 另外一部分是类型指针,如果是java数组的话还必须保存一个数组的长度信息
实例数据
对齐填充

扫描对象是否已死,
引用计数法,有个问题是循环引用,会出问题
可达性分析:
GCRoot来说有三种:栈中的变量,常量,静态变量
引用有四种:Strong,weak,phantom
在第一次被GC扫到一个变量没有引用了,就会去调用他的finalize,这时只要重新将他关联到某个某个变量上就能防止被回收
但是只有第一次会去调用这个finalize这个方法

复制算法:一块eden:8 两块survivor:1 
每次清空eden和一块survivor,放到预留的那一块上面,如果没有了就放到老年代上面

GC器分为年轻代和老年代的两种:
serial,serial old: 就是在

ParNew是除了serial之外唯一能和CMS一起运作的GC,-XX:+UserConMarkSweepGC
-XX:+UseG1GC
-XX:+UserParNewGC可以强制指定年轻代使用Par
-XX:ParallelGCThreads 可以强制限定GC的线程数

Parallel并行,可能还是需要调度的
Concurrent并发,可能纯粹就是在不同的CPU上面跑了

serial,par都是用的Mark-Compact

初始标记,重新标记仍然需要stw
CMS:初始标记(GC ROOTS),并发标记(GC root tracing),重新标记(第一次没有清楚成功再删),并发清楚

G1整理上是标记-整理算法来实现的,局部上(两个region之间)又可以使用 复制
G1 将整个空间化成不同的region

一般新的对象会放在eden空间当中,当eden当中没法分配的时候就会转到老年代里面去。
Minor GC一般是针对新生代的
Major GC一般是针对老年代的

PretenureSizeThreshold是指超过这个值的对象会直接分配到老年代上面去

在往survivor里面放一次,年龄就增加1,使用MaxTenuringthreshold就可以决定到多少年龄可以被放到老年代当中


GC可能遇到的坑:
1,如果heap的值设置得太大了,每次GC消耗得时间就会很长

使用jstat -gcutil 进程号 

可以看到gc相关的信息

猜你喜欢

转载自blog.csdn.net/zhoucs86/article/details/90113719