tomcat jvm mem manager
jvm内存管理及相关设置
https://cloud.tencent.com/developer/article/1141496https://www.cnblogs.com/rsapaper/p/10452541.htmlhttps://juejin.cn/post/6950971239972208647https://www.cnblogs.com/Jack-Blog/p/14332247.htmlhttps://www.cnblogs.com/Jack-Blog/p/14481982.htmlhttps://www.cnblogs.com/Jack-Blog/p/14853396.htmlhttps://www.cnblogs.com/jichi/p/12580906.html

简化JVM 的逻辑内存模型

java.app –> javac –> java.class –> jvm
类定义:事务操作的接口,可以共享
方法:相同的类属性赋予不同的值,表示不同的对象,调用方法相同
JAVA堆栈
栈:用于存储局部变量表、操作栈、动态链接、方法出口等信息。每一个方法被调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程(存放变量,程序运行逻辑)
堆:被所有线程共享的一块内存区域,在虚拟机启动时创建。此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存(存放文件的数据,或JAVA运行的对象等)
主要分为两部分:JVM 执行引擎、类加载器
JVM运行时,通过类加载器,把所有使用的类加载到内存,将所有使用的类装入内存,类初始化对象实例,并将其置于内存中
JAVA/JVM运行时区域,方法区、堆内存,所有的JAVA线程共享
方法区:是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据(放各个类的方法,共享给对象使用,只能同一类对象,才调用同一类的方法)
堆,各式各样的对象都存放在堆内存空间
JAVA栈:PC寄存器(程序计数器)、本地方法栈都是线程私有
JAVA栈:程序使用的空间主要是堆栈,栈存放全局变量和数据,因此程序逻辑,不同线程逻辑还是有区别的
PC寄存器,程序指针,程序指令切换不同的线程运行
本地方法栈,调用节点自己系统方法接口,以避免JAVA程序的移植性被破坏,并尽量少调用本地方法
Android是JAVA程序,运行在JVM上,运行逻辑和JAVA有一定的区别,但底层差不多
APP –> Android – > jvm –> 用户空间 –> 内核
性能损耗大约30%
JAVA对程序员只申请内存不用管理释放内存,JAVA会自动释放内存
GC(垃圾收集器) –> 堆
内存算法
引用计数算法
当引用计数为0时清理
每个对象都有引用指针,一个对象被引用几次,引用是有计数器的,如果对象的计数为0,表示可以垃圾回收,这是一种古老的回收算法,有致命的缺陷,没法处理循环应用
标记-清除(Mark-sweep)算法
垃圾回收分两个阶段
第一阶段:整理堆内存中标记所有对象被引用的测试;
第二阶段:在完成标记后遍历整个堆,如果没有引用则释放,释放会产生碎片内存,从而减少内存碎片
复制算法( Copying )算法
堆内存表示将内存划分为两块区域AB,一次仅使用一半,对半分
所有的对象对存放在第一段区域A,当满了或策略变更区域段,找到存活的并复制第二段B,这种算法会额外浪费内存空间,不能充分合理利率资源,且复制也会造成性能损耗
标记-整理(Mark-Compact)算法
两个阶段
第一阶段:整理堆内存中标记所有对象被引用的测试;
第二阶段:在完成标记后遍历整个堆,未标记的对象压缩,移动或交换到一个邻近的内存空间形成一段连续的空间,为了减少内存碎片
无论哪种算法都需要遍历堆内存,这是共性
当一个对象数据发生改变,复制会产生不完成,为了避免这个问题,如何解决?
JAVA:停止所有工作线程,仅运行GC线程,等GC结束,在让线程工作(STP:Stop The World)
每一次Full GC回收都需要一次STP
回收方式
按照内存空间划分处理,如何使用并更方便地清理空间,分割多个内存空间
增量收集:实时垃圾回收,已经过时,1.5版本之前使用
分代收集:当前关注,最广泛
分代垃圾收集器逻辑

1、新生代,新创建的对象 Eden SS1 SS2
2、老年代,存活时间较长的 Old
3、持久代,没必要清理 perm
- 例:标记复制算法 App –> Eden –> SS1 –> SS2 –> Old –> Perm(1.8版本后没有持久代的说法) 1、新生的对象都放入 Eden区,当空间满时,标记存活的应用复制到SS1区,其他Eden区域释放 2、新生的对象都放入Eden区,当空间满了,这次扫描两个区域Eden、SS1,标记存活的都复制到SS2区,剩下的做释放 3、新生的对象都放入Eden区,当空间满了,这次扫描两个区域Eden、SS2,标记存活的复制到SS1区,剩下的做释放,若上一次的SS1对象存活一次,SS2也存活一次,下次会放入到Old区域(简单来说就是存活跳跃2次标记得到到Old区域) 4、SS1、SS2身份会来回切换,源FROM、目标TO 大部分的对象在第一阶段都完成回收,因此新生代回收很频繁,根据实际情况可增加空间 当老年代空间满时,很久才会满,而且回收较慢,若不太频繁,可根据实际情况分配此空间,可适当缩小此空间 由于full gc全堆时间的垃圾回收,时间较长,卡顿较长,因此需要定义内存空间的大小,减少 full gc的次数,避免对系统造成影响 如果区域都存活可能是内存空间小了,不考虑极端情况
Major gc 标记整理算法,效率低不会产生内存碎片
Minor gc 复制算法,分代完成
收集器工作情景
串行收集器:单线程收集垃圾(一般客户端使用,当然也可以并行)
并行收集器:多线程同时工作(一般用于科学计算)
并发收集器:回收过程当中,线程不停止工作做回收,回收是分阶段的,有阶段有条件的并发,不是真正的并发(并发一般是对响应时间有影响,缩短响应用户的请求)
1、内存空间设定,包括各种空间的比例切分
2、针对不同代别和业务场景,选择最合适的垃圾收集器算法
The memory structure of a JVM process

PS Eden Space
PS Old Gen
PS Survivor Space 存活区
Code Cache 代码缓存
Compressed Class Space 压缩类空间
Metaspace 元空间
垃圾回收算法
新生代
Serial 序列 串行
ParNew 并行
Paraller Scavenge 吞吐量
老年代
Serial Old:单GC线程回收老年代中不再被使用的对象
Parallel Old:多GC线程回收老年代中不再被使用的对象
CMS(Concurrent Mark Sweep):以获得最短回收停顿时长为目标,是互联网站点服务端的B/S系统上较佳的回收算法;标记-清除
G1:Gabage First 并行和并发,分代收集,空间整合,可预测停顿(新算法)
整理过程分四个阶段
初始标记 串行
并发标记 并发
重新标记 串行
并发清除 并发
指定垃圾收集器
辅助定义工作逻辑
ParalessGCThreads:并行GC线程的数量
调试可开启,调试完一定要关闭,会产生大量的日志IO
显示垃圾回收的统计信息:
例:指定算法时,注意需要+号
JVM常用分析工具
JAVA程序相当于黑盒,运行在JVM中
jps 列出目标系统上已检测的 Java 虚拟机 (JVM),查看JAVA进程状态
jinfo 输出给java进程所有配置信息
jstack 查看java进程、核心文件或远程调试服务器的 Java 线程堆栈跟踪
jmap 打印进程、核心文件或远程调试服务器的共享对象内存映射或堆内存详细信息
jstat 监控 Java 虚拟机 (JVM) 统计信息
图形化工具 jconsole
组件JMX,外部程序是通过JMX接口来监控
jmx: java Management eXtensions
tomcat常用优化配置
1、设定内存空间
2、线程池设置
3、根据实际情况设定关闭不必要的协议
http https ajp(二进程协议)
前端若是nginx,那么关闭http
前端若是httpd,使用ajp,浏览器是无法识别ajp协议的,无法绕过代理服务器
4、禁用8005端口
5、隐藏版本信息
小结
tomcat优化大致分为两部分
1、JVM 优化层级维度 内存设定,垃圾回收设定,TOMCAT线程池设定
2、连接线程优化程序级优化,一般不是运维做的,开发做的
也不要过度优化
YGC次数和YGCT时长累加
说明YGC过于频繁,要能空间小了
OLDGC很慢,说明空间比例分割有问题
如果两种都很慢,说明总体空间有问题
若YGC过于频繁,疑点元区和存活分区分配有问题,默认还好,存活区占用很小,1.0分区很大,说明失衡了,增加1.0区大小,减少存活区的大小
用于二进制软件包
JAVA\_OPS选项定义在脚本首部即可
JAVA\_HOME 指定JAVA家目录
tomcat配置语法检查 configtest
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 438803792@qq.com
Loading...
keepalived