Tomcat优化

目录

一、JVM

[1.1.JVM 组成](#1.1.JVM 组成)

1.2.JVM运行时数据区域由下面部分构成

[二、Garbage 垃圾确定方法](#二、Garbage 垃圾确定方法)

2.1.垃圾回收基本算法

[2.1.1标记-清除 Mark-Sweep](#2.1.1标记-清除 Mark-Sweep)

[2.1.2.标记压缩 (压实)Mark-Compact](#2.1.2.标记压缩 (压实)Mark-Compact)

[2.1.3 复制 Copying](#2.1.3 复制 Copying)

2.1.4多种算法总结

[2.1.5 STW](#2.1.5 STW)


一、JVM

1.1.JVM 组成

  • 类加载子系统: 使用Java语言编写.java Source Code文件,通过javac编译成.class Byte Code文件。class loader类加载器将所需所有类加载到内存,必要时将类实例化成实例

  • 运行时数据区: 最消耗内存的空间,需要优化

  • 执行引擎: 包括JIT (JustInTimeCompiler)即时编译器, GC垃圾回收器

  • 本地方法接口: 将本地方法栈通过JNI(Java Native Interface)调用Native Method Libraries, 比如:C,C++库等,扩展Java功能,融合不同的编程语言为Java所用

1.2.JVM运行时数据区域由下面部分构成

  • **Method Area (线程共享):**方法区是所有线程共享的内存空间,存放已加载的类信息(构造方法,接口定义),常量(final),静态变量(static), 运行时常量池等。但实例变量存放在堆内存中. 从JDK8开始此空间由永久代改名为元空间

  • heap (线程共享): 堆在虚拟机启动时创建,存放创建的所有对象信息。如果对象无法申请到可用内存将抛出OOM异常.堆是靠GC垃圾回收器管理的,通过-Xmx -Xms 指定最大堆和最小堆空间大小

  • **Java stack (线程私有):**Java栈是每个线程会分配一个栈,存放java中8大基本数据类型,对象引用,实例的本地变量,方法参数和返回值等,基于FILO()(First In Last Out),每个方法为一个栈帧 1 50 %

  • **Program Counter Register (线程私有):**PC寄存器就是一个指针,指向方法区中的方法字节码,每一个线程用于记录当前线程正在执行的字节码指令地址。由执行引擎读取下一条指令.因为线程需要切换,当一个线程被切换回来需要执行的时候,知道执行到哪里了

  • **Native Method stack (线程私有):**本地方法栈为本地方法执行构建的内存空间,存放本地方法执行时的局部变量、操作数等。

二、Garbage 垃圾确定方法

  • 引用计数: 每一个堆内对象上都与一个私有引用计数器,记录着被引用的次数,引用计数清零,该对象所占用堆内存就可以被回收。循环引用的对象都无法将引用计数归零,就无法清除。Python中即使用此种方式。 简单来说就是有个笔记本,记录有没有人在用,缺陷,AB 资源互相调用

  • 根搜索(可达)算法 Root Searching

2.1.垃圾回收基本算法

2.1.1标记-清除Mark-Sweep

分垃圾标记阶段和内存释放阶段。标记阶段,找到所有可访问对象打个标记。清理阶段,遍历整个堆,对未标记对象(即不再使用的对象)逐一进行清理。

标记-清除最大的问题会造成内存碎片,但是不浪费空间,效率较高(如果对象较多,逐一删除效率也会影响)

2.1.2.标记压缩 (压实)Mark-Compact

分垃圾标记阶段和内存整理阶段。标记阶段,找到所有可访问对象打个标记。内存清理阶段时,整理时将对象向内存一端移动,整理后存活对象连续的集中在内存一端。

标记-压缩算法好处是整理后内存空间连续分配,有大段的连续内存可分配,没有内存碎片。缺点是内存整理过程有消耗,效率相对低下

2.1.3 复制 Copying

先将可用内存分为大小相同两块区域A和B,每次只用其中一块,比如A。当A用完后,则将A中存活的对象复制到B。复制到B的时候连续的使用内存,最后将A一次性清除干净。缺点是比较浪费内存,只能使用原来一半内存,因为内存对半划分了,复制过程毕竟也是有代价。好处是没有碎片,复制过程中保证对象使用连续空间,且一次性清除所有垃圾,所以效率很高。

2.1.4多种算法总结

没有最好的算法,在不同场景选择最合适的算法

  • 效率: 复制算法>标记清除算法> 标记压缩算法

  • 内存整齐度: 复制算法=标记压缩算法> 标记清除算法

  • 内存利用率: 标记压缩算法=标记清除算法>复制算法

2.1.5 STW

对于大多数垃圾回收算法而言,GC线程工作时,停止所有工作的线程,称为Stop The World。GC 完成时,恢复其他工作线程运行。这也是JVM运行中最头疼的问题。

三、分代堆内存GC策略

3.1.年轻代回收Minor GC

  1. 起始时,所有新建对象(特大对象直接进入老年代)都出生在eden,当eden满了,启动* *GC**。这个称为** Young GC 或者 Minor GC

  2. 标记 eden存活对象,然后将存活对象复制 到s0(假设本次是s0,也可以是s1,它们可以调换),eden剩余所有空间都清空。GC完成

  3. 继续新建对象,当eden再次满了,启动GC

  4. 先同时标记 eden和s0中存活对象,然后将存活对象复制 到s1。将eden和s0清空,此次GC完成

  5. 继续新建对象,当eden满了,启动GC

  6. 标记 eden和s1中存活对象,然后将存活对象复制 到s0。将eden和s1清空,此次GC完成以后就重复上面的步骤。

通常场景下,大多数对象都不会存活很久,而且创建活动非常多,新生代就需要频繁垃圾回收。但是,如果一个对象一直存活,它最后就在from、to来回复制,如果from区中对象复制次数达到阈值(默认15次,CMS为6次,可通过java的选项 -XX:MaxTenuringThreshold=N 指定),就直接复制到老年代。

3.2.老年代回收 Major GC

进入老年代的数据较少,所以老年代区被占满的速度较慢,所以垃圾回收也不频繁。如果老年代也满了,会触发老年代GC,称为Old GC 或者 Major GC

由于老年代对象一般来说存活次数较长,所以较常采用标记-压缩算法。

当老年代满时,会触发 Full GC,即对所有"代"的内存进行垃圾回收

Minor GC比较频繁,Major GC较少。但一般Major GC时,由于老年代对象也可以引用新生代对象,所以先进行一次Minor GC,然后在Major GC会提高效率。可以认为回收老年代的时候完成了一次Full GC。所以可以认为 MajorGC = FullGC

相关推荐
ruanjiananquan996 分钟前
c,c++语言的栈内存、堆内存及任意读写内存
java·c语言·c++
chuanauc33 分钟前
Kubernets K8s 学习
java·学习·kubernetes
一头生产的驴1 小时前
java整合itext pdf实现自定义PDF文件格式导出
java·spring boot·pdf·itextpdf
YuTaoShao1 小时前
【LeetCode 热题 100】73. 矩阵置零——(解法二)空间复杂度 O(1)
java·算法·leetcode·矩阵
zzywxc7871 小时前
AI 正在深度重构软件开发的底层逻辑和全生命周期,从技术演进、流程重构和未来趋势三个维度进行系统性分析
java·大数据·开发语言·人工智能·spring
YuTaoShao3 小时前
【LeetCode 热题 100】56. 合并区间——排序+遍历
java·算法·leetcode·职场和发展
程序员张33 小时前
SpringBoot计时一次请求耗时
java·spring boot·后端
llwszx6 小时前
深入理解Java锁原理(一):偏向锁的设计原理与性能优化
java·spring··偏向锁
云泽野7 小时前
【Java|集合类】list遍历的6种方式
java·python·list
二进制person7 小时前
Java SE--方法的使用
java·开发语言·算法