jvm - GC roots & 参数调优与命令

jvm - GC roots & 参数调优与命令

什么是垃圾:内存中不再被使用到的空间。
如何确定是不是垃圾:引用计数法、用枚举根节点做可达性分析。
枚举根节点是一系列名为GC roots的对象集合(一组活跃的引用),作为起始点,它们下面连着的叫引用可达对象,没连着的叫引用不可达对象。

哪些对象属于GC root Set?

jvm - GC roots & 参数调优与命令

(???字符串常量池在方法区中吗)(jdk1.6的时候还在(此时为永久代))(jdk1.7,字符串常量池被移动到了堆中)
代码举例:

jvm - GC roots & 参数调优与命令

new GCRootDemo()就是虚拟机栈(栈中的本地变量表)中引用的对象;
private static GCRootDemo2 t2就是方法区中的类静态属性引用的对象;
private static final GCRootDemo3 t3 = new GCRootDemo3()就是方法区中常量引用的对象;
Q:问题来了:???类静态属性、常量的引用变量不是放在虚拟机栈中的,而是放在方法区中的吗?
A:对的,方法区中存放的东西,除了有类的模板信息,还有类静态属性、类型为常量的引用变量等。

 


jvm - GC roots & 参数调优与命令

小小回顾一下之前学的:
之前学过 -Xms -Xmx -Xmn -XX:PermSize -XX:MaxPermSize -XX:+PrintGCDetails
这些调参优化,都在IDEA

jvm - GC roots & 参数调优与命令

中设置。

新知识:
jps -l 查看windows下当前正在运行的Java程序(linux中为 ps -ef | grep java)

jvm - GC roots & 参数调优与命令

数字为进程号

jinfo -flag XXX(如 PrintGCDetails) 进程号  :看进程号为...的Java程序(需要该Java程序已经开启,不然不会有进程号)是否开启了XXX或者XXX等于多少(结果根据XXX是Boolean类型还是kv类型)
XXX都是以-XX:开头的,像-Xms、-Xmx、-Xmn不能用,这些只能在IDEA中配置,不能用在    jinfo -flag XXX 进程号   中。

举一个Boolean类型的例子:
(-XX:+PrintGCDetails)

jvm - GC roots & 参数调优与命令

jvm - GC roots & 参数调优与命令

举一个kv类型的例子:
(-XX:MetaspaceSize=1024m)(而默认值如下图所示,约21兆)

jvm - GC roots & 参数调优与命令

-XX:MaxTenuringThreshold=xx 设置最多被GC的次数,超过该阈值则不再在From To区中来回倒了,而是进入老年区。
(而年轻代到老年代的GC,所以只发生在年轻代,而年轻代又只使用复制算法,所以这个参数就是指经历复制算法最多多少次后会被放进老年代)

jvm - GC roots & 参数调优与命令

jinfo -flag XXX(如 PrintGCDetails) 进程号
升级——>
jinfo -flags 进程号    查看进程号...的Java程序的所有信息

另外

jvm - GC roots & 参数调优与命令

所以其本质还是-XX型的参数,用于调整火腿肠(即堆内存大小)一开始多长,最大有多长(默认1/4   1/64)
而-Xmn用于调整火腿肠的young old的配方比例(默认1:2)

如何查看JVM的初始默认参数
在cmd中,直接输入 java -XX:+PrintFlagsInitial

jvm - GC roots & 参数调优与命令

如何查看JVM的修改更新参数
在cmd中,直接输入 java -XX:+PrintFlagsFinal

= 说明是JVM默认加载的,没改过
:= 说明是用户或JVM修改过的更新值
(上图都是= ,所以这些值都是没改过的)

java -XX:+PrintCommandLineFlags -version
结果中可以看到JVM使用的是什么垃圾回收器

 

 

jvm - GC roots & 参数调优与命令

-Xms -Xmx
在程序中可由..获取:
Runtime.getRuntime().totalMemory(); //返回Java虚拟机中的内存总量(即堆内存)
Runtime.getRuntime().maxMemory(); //返回Java虚拟机试图使用的最大内存量(即堆内存)
等价于 -XX:InitialHeapSize=
            -XX:MaxHeapSize=

jvm - GC roots & 参数调优与命令


-Xss 设置单个(单个是因为栈在架构图中是灰色的,是私有的)线程栈空间的大小,一般默认为512k~1024k,等价于
-XX:ThreadStackSize,但是不加任何修改,查看初始栈大小,发现ThreadStackSize=0?

jvm - GC roots & 参数调优与命令

原因:平台不同,结果不同,512k~1024k一般是指linux等其它系统。

    *-Xmn 学过,设置香肠中新生代占总香肠的比例,原来默认新生代:老年代=1:2,一般不修改。
    *-XX:MetaspaceSize

jvm - GC roots & 参数调优与命令

永久代和元空间最大的区别:
永久代使用的内存是Java虚拟机的堆内存;
元空间使用的内存是本机的物理内存。(所以,默认情况下元空间的大小仅受本地内存的限制)

jvm - GC roots & 参数调优与命令

(永久代在逻辑上、物理上都属于堆空间
元空间在逻辑上、物理上都不属于堆空间)
物理上属不属于的依据就是使用JVM的堆内存还是本机的物理内存
永久代和元空间都是对方法区的一个实现

 

但即使元空间使用本机物理内存,还是可能
报错:java.lang.OutOfMemoryError:Metaspace
原因:虽然机器物理内存16G,但是初始设置元空间大小可能只有几十兆,即虽然元空间大小与JVM内存无关,仅与本地内存有关,但还是要受到默认元空间大小的限制
办法:往往把元空间设大一点(通过-XX:MetaspaceSize=xxx)
即虽然说jdk1.8中方法区的实现:元空间物理上不属于jvm堆空间,使用物理内存(如8G),但jvm还是对方法区有一个初始空间大小的设置,初始只有几十兆。可通过
-XX:MetaspaceSize=1024来调整

把上面讲过的调参命令,合在一起用一下、配一下(写在IDEA中进行配置):
即JVM的配置案例:

jvm - GC roots & 参数调优与命令

SerialGC:这里设置使用串行垃圾回收器,默认一般使用并行垃圾回收器(涉及垃圾回收器硬件实现,以后会讲)

    *-XX:PrintGCDetails 打印GC细节,+改成-就是不打印的意思。


故意使坏,把堆的初始和最大值设为10M,通过new byte[50*1024*1024]就能把堆撑爆,就会报OOM,并显示GC、Full GC  
显示规律:

jvm - GC roots & 参数调优与命令
    * -XX:NewRatio=一个整数(默认是2,1:2)     感觉和-Xmn是一个东西(设置具体大小,带上单位M)

调新生代占火腿肠多少比例(默认是新生代:老年代=1:2)
调参设置后 新生代:老年代=1:一个整数(默认是2)

 

    * -XX:SurvivorRatio=一个整数(默认是8,8:1:1)

比调新生代区占火腿肠多少比例还要细:调的是新生代自己内部的比例!(默认 伊甸区:S0:S1=8:1:1)
调参设置后 伊甸区:S0:S1=一个整数:1:1

 

    *-XX:MaxTenuringThreshold        (必须在0-15之间)
如果设置为0的话,则年轻代对象不经过survivor区,直接进入老年代。

jvm - GC roots & 参数调优与命令