一.jdk体系结构
二. java语言跨平台的特性
三.jvm内存模型及结构分析
1.jvm内存模型总览
2.关于虚拟机栈的理解分析
虚拟机栈
对象执行方法时会执行下面几个操作
一.先是为主方法开辟一个线程空间,同时分配好可伸缩的内存空间
二.是从栈的局部变量表中拿到局部变量,从操作数栈中的得到操作数为局部变量赋值
三.计算的时候会把操作数栈中对应的数取出来到cpu中进行运算之后,把得到的结果拿出栈给局部变量表赋值
注意事项:程序计数器代表每次执行一步操作之后加一为程序的步数。程序计数器设计的目的是为了在多线程情况下挂起线程再激活的时候不用再重新对程序再重新计算。并且在递归调用下也是并行的分配内存,而不是嵌套分配内存空间。
根据javap命令编译类到指定路径得到更容易理解的java字节码文件
指令:javap -c math.class>math.text
如下
部分jvm指令对照
2.关于堆的理解分析
堆模型
堆按照分代模型分为三个模块
伊甸区: 伊甸区类加载器的对象首先会被保存到eden区,如果伊甸区的对象总量大于一定的值会发生minorGC会导致对象转移到两个s区中
首尔区:两个首尔区大小几乎一致但是是先通过第一个s0再到s1区
老年代:一般大对象或者引用比较深的对象会被分配到这个区域,老年代大概占总分代的2/3.
swt的概念
swt是指如果发生GC的时候,垃圾回收器会把所有的用户线程暂时挂起,会让用户感觉网站卡了一下的感觉,同时swt也是性能优化和程序耗时的关键。
为什么要设计swt?
如果不设计swt的话,刚刚通过垃圾GCroot分析得到的非垃圾对象在用户操作中该方法已经结束导致刚刚分析的对象全部出栈导致这些对象全部变为垃圾对象,这样就失去了垃圾回收的意义。
元空间
这里用来放置常量,方法的引用符号,类的符号等信息
注意事项:元空间默认分配物理内存并且初始容量为21M,如果数据超过21M会导致fullGC并且会让元空间动态伸缩。如果一个项目非常大,并且启动很慢的话,很可能是元空间过小导致多次的fullGC和扩容,此时需要调整jvm参数元空间的大小。一般会设置为:‐XX:MetaspaceSize=256M ‐XX:MaxMetaspaceSize=256M
本地方法栈
主要是c++实现的java中用native关键词修饰的方法用来开启线程和保存变量的地方,通常调用本地的dll文件库。
程序计数器/pc寄存器
主要用来记录每个线程执行的步数,由字节码驱动引擎来操作。
三.JVM内存参数设置
spring Boot程序的JVM参数设置格式(Tomcat启动直接加在bin目录下catalina.sh文件里):
1 java ‐Xms2048M ‐Xmx2048M ‐Xmn1024M ‐Xss512K ‐XX:MetaspaceSize=256M ‐XX:MaxMetaspaceSize=256M ‐jar microservice‐eurek a‐server.jar
关于元空间的JVM参数有两个:-XX:MetaspaceSize=N和 -XX:MaxMetaspaceSize=N
-XX:MaxMetaspaceSize: 设置元空间最大值, 默认是-1, 即不限制, 或者说只受限于本地内存大小。
-XX:MetaspaceSize: 指定元空间触发Fullgc的初始阈值(元空间无固定初始大小), 以字节为单位,默认是21M,达到该值就会触发 full gc进行类型卸载, 同时收集器会对该值进行调整: 如果释放了大量的空间, 就适当降低该值; 如果释放了很少的空间, 那么在不超 过-XX:MaxMetaspaceSize(如果设置了的话) 的情况下, 适当提高该值。这个跟早期jdk版本的-XX:PermSize参数意思不一样,- XX:PermSize代表永久代的初始容量。 由于调整元空间的大小需要Full GC,这是非常昂贵的操作,如果应用在启动的时候发生大量Full GC,通常都是由于永久代或元空间发生 了大小调整,基于这种情况,一般建议在JVM参数中将MetaspaceSize和MaxMetaspaceSize设置成一样的值,并设置得比初始值要大, 对于8G物理内存的机器来说,一般我会将这两个值都设置为256M。
StackOverflowError示例:
结论: -Xss设置越小count值越小,说明一个线程栈里能分配的栈帧就越少,但是对JVM整体来说能开启的线程数会更多