跨平台特性

“一次编写,到处运行”

跨平台特性如何实现的?

通过不同版本和平台的JVM,将字节码文件编译成不同机器代码。
image.png

三大组成

类装载子系统 + 运行时数据区(最核心) + 字节码执行引擎

运行时数据区(内存模型)

image.png

栈(线程)

之所以叫线程栈,是因为会为不同的线程分配不同的空间来存储局部变量。不同线程之间是互不干扰的。

栈帧

即为每个方法分配的一块内存空间。

栈帧内主要放以下数据:

  1. 局部变量表(存局部变量的);
  2. 操作数栈(存数值的);
  3. 动态链接
  4. 方法出口,存放方法执行完之后,要返回到哪里接着执行的信息;

为什么是栈结构?

因为和程序调用的逻辑很吻合,例如main方法中调用了compute方法,那么首先,

  1. main入栈,compute入栈,
  2. compute调用结束,compute出栈,
  3. main方法调用结束,main出栈。

程序计数器

其实和计数无关,是用来保存当前执行或者即将要执行的下一条指令的地址。

为什么需要程序计数器?

因为JAVA中存在多线程,在A线程执行的过程中,如果B线程抢走了CPU,等回到A线程时,需要知道接下来执行的指令的地址,因此需要用程序计数器保存下来。这里也可以看出来,每一个线程都有自己的程序计数器。

堆主要用来存放new出来的对象。

结构如下:
image.png
即年轻代 + 老年代。年轻代由Eden区 + Survivor区组成。

对象会不停的放进Eden区,当Eden区满了以后,触发minor gc. minor gc 会尝试回收年轻代中的垃圾。

堆和栈的关系

栈中可能要用到某个对象,该对象是存放在堆中的,栈里只保存该对象的内存地址。

方法区

主要放置常量(final修饰),静态变量(static修饰)以及类信息。

本地方法栈

用来保存本地方法(native修饰)
本地方法栈同样也是每个线程一份

GC的过程

GC主要涉及到的是堆,因为GC是回收垃圾对象,次要涉及方法区。

Minor GC

触发条件: 对象会不停的放进Eden区,当Eden区满了以后,触发minor gc. minor gc 会尝试回收年轻代中的垃圾。

过程:
通过可触达分析算法,即通过GC root往下找,能触达的对象标记为不是垃圾,其他的不能触达的对象将被回收。不是垃圾的对象将会移动到s0或者s1中(来回移动)。此外,每经历一次minor gc, 这些不是垃圾的对象的年龄会加1, 当年龄到达15时,如果还没被回收,就会被移动到老年代。

Full GC

触发条件:老年代满了

过程:和Minor GC差不多,只是回收整个堆以及方法区

Stop the word (STW)

即在执行GC时,会停止用户的所有线程,因此用户会觉得卡顿。那么如果GC次数越多,耗时越长,用户体验越差。

既然如此,为什么要有STW?
反过来想,如果没有STW,用户的线程和GC并行,那么某一些数据不会被标记为垃圾,因为可能正被GC ROOT 引用着,然而当用户线程结束时,这些数据应该被释放掉,但是因为没有被标记为垃圾,所以GC不会回收这部分数据。因此,需要STW来应对这种情况。

内存参数设置

image.png

  1. java Xms2048M Xmx2048M Xmn1024M Xss512K XX:MetaspaceSize=256M XX:MaxMetaspaceSize=256M jar microserviceeurek
  2. aserver.jar