Tomcat (7) -JVM and memory management

.JVM a virtual machine

Written in Java .javaSource Code files compiled by javac .class
Byte Code files, JVM can identify .classfiles, and use the JIT compiler to .class
run the machine code file is compiled.

class loader 类加载器: The required class is loaded into memory, if necessary, into the instance of the class instance.

FIG intermediate portion is in the process of the logical structure of memory, referred Jvm running region, consists the following parts:

Method AreaMethods District: All threads share memory space to store class information, constants and static variables are loaded.

HeapHeap: All threads share memory space to store all the objects created. By GC heap is managed by the garbage collector.

Java StackStack: Each thread is assigned a stack, with the thread store local variables, method parameters and return values.

PC 寄存器: PC, i.e., Program Counter, each thread used for recording bytecodes currently executing thread
instruction address. Because the thread switch requires that when a thread is switched back to be executed, to know where the execution.

本地方法栈: The method of performing a local memory space constructed, when the local variable storage method performed locally, the number of operations.

The so-called local method, simply method is non-Java implementation, such as the local operating system written in C library provides
methods, Java native method call these interfaces to perform. Note, however, local programming method should avoid direct use,
because the cross-platform Java may, if the Windows API, change to the Linux platform deployments have a problem.

II. Memory garbage collection

2.2 GC memory garbage collector

Heap memory which often create, destroy objects, high-frequency memory to be used, to be released. If not properly treated, a
frequently used process, will likely have memory, but was unable to allocate the available memory space, because there is no continuous address
memory area, the memory is all fragmented data. Therefore, JVM's GC that is used to solve such problems.

2.2.1 GC memory recall basic arithmetic

1. The reference count

All with reference to a private object is within each pile the counter, recording the number of times referenced, the reference count is cleared, the object
heap memory occupied by it can be recovered. Object circular references are not reference count to zero, it can not be cleared.

2. Mark - Clear Mark-Sweep

As the name suggests, mark and sweep garbage collector has two stages

  1. Mark phase
    mark phase, find all accessible objects to make a mark. Note that, in the mark phase, it will stop the application
    threads to make changes to avoid the object state during the mark phase.

  1. Clear stage
    clean-up stage, through the entire stack of unlabeled objects cleanup. In the cleanup phase, all unmarked from the stages of the mark
    as deleted from memory, freeing up space.

As can be seen from the above figures, there may be a large amount of available memory region after the purge stage. However, because these internal
memory is small pieces of debris, if the next memory allocation is larger than all the existing free area, so it might allocation failure.
Therefore, it is necessary to introduce a third phase, the compression phase.

3. Mark - Clear - Compression Mark-Sweep-Compact

Minute mark phase of garbage and memory consolidation phase. Mark phase, find all accessible objects to make a mark. Memory scrubbing
time stage, when the object is moved to the finishing end of memory, live objects in memory at one end continuous focus on finishing.

mark

Remove

Compression Finishing: After scanning stage, all memory locations will be rearranged to provide a more compact memory allocation. This approach
drawback is that GC pause time is increased, because it needs to copy all objects to a new location and updates to these objects
all references.

From the above chart, 标记-清除-压缩the algorithm benefit is continuous allocate memory space after finishing, continuous large segment of the
memory can be allocated, no memory fragmentation. The disadvantage is that memory consolidation process has consumed.

4. Mark - Copy Mark-Copying

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

这种垃圾回收机制类似于标记-清除,但内存空间分为两部分。最初,将对象分配给一个
内存空间(fromspace),并标记活动对象。

在复制阶段,被标记的对象被复制到另一个内存空间(tospace),同时被压缩。然后,
fromspace 被清空。

5. 分代收集算法

既然上述垃圾回收算法都有优缺点,能不能对不同数据进行区分管理,不同分区对数据实施
不同回收策略,分而治之?Tomcat 中 JVM 使用堆内存的分代回收机制来针对不同数据区域
进行内存回收。
Tomcat1.7 及以前,堆内存分为新生代、老年代、持久代。
Tomcat1.8 开始,持久代没有了,取而代之使用 MetaSpace。

在分代垃圾回收中,内存空间被划分为不同的代(如年轻代和老年代)。最初,所有的对象将
驻留在年轻代。然而,当垃圾收集周期发生时,在垃圾回收之后存活的对象将被提升到
老年代。

一次 Minor Collection 回收(新生代回收)前

一次 Minor Collection 回收后

回收后,可以清除年轻代中遗留的对象,因为所有活动对象都将移动到老代中。

老一代的垃圾回收周期比年轻一代的长。这种方法背后的关键思想是,在第一次垃圾收集后
存活下来的对象往往寿命更长。因此,可以减少老一代对象的垃圾收集频率。代的数量因编
程语言的不同而不同。例如,在 Java 中有两代,在.NET 中有三代。

2.2.2 STW

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

2.2.3 垃圾收集器类型

按回收线程数个数分为:

  • 串行垃圾回收器:一个 GC 线程完成回收工作
  • 并行垃圾回收器:多个 GC 线程同时一起完成回收工作,充分利用 CPU 资源

按工作模式不同:

  • 并发垃圾回收器:让 GC 线程垃圾回收某些阶段可以和工作线程一起进行。
  • 独占垃圾回收器:只有 GC 在工作,STW 一直进行到回收完毕,工作线程才能继续执行。
一般情况下,抉择串行还是并行我们大概可以使用以下原则:
客户端或较小程序,内存使用量不大,可以使用串行回收;
对于服务端大型计算,可以使用并行回收;
大型 WEB 应用,用户端不愿意等,尽量少的 STW,可以使用并发回收;

三.JVM 堆内存回收

3.1 JVM 内存模型

JVM 内存模型图示

堆内存在 JVM 使用的内存中占比最大,Heap 堆内存分为:

  1. 新生代:刚刚创建的对象
  2. 伊甸园区
  3. 存活区 Servivor Space:有 2 个存活区,一个是 from 区,一个是 to 区。
    它们大小相等、地位相同、可互换。to 指的是本次复制数据的目标区
  4. 老年代:长时间存活的对象
  5. 持久代:JVM 的类和方法

3.2 JVM 堆内存回收

如 2.1 中 JVM 内存模型图所示

新生代回收
起始时,所有新建对象都出生在 eden,当 eden 满了,启动 GC。这个称为 Young GC
Minor GC。先标记 eden 存活对象,然后将存活对象复制到 s0(假设本次是 s0,也可以
是 s1,它们可以调换),eden 剩余所有空间都"清空",GC 回收内存完成。
继续新建对象,当 eden 满了,启动 GC。先标记 eden 和 s0 中存活对象,然后将存活对
象复制到 s1。将 eden 和 s0 “清空”。继续新建对象,当 eden 满了,启动 GC。先标记
eden 和 s1 中存活对象,然后将存活对象复制到 s0。将 eden 和 s1 “清空”。
以后的内存回收重复上面步骤。

大多数对象都不会存活很久,而且创建活动非常多,新生代就需要频繁垃圾回收。但是,如果
一个对象一直存活,它最后就在 from、to 来回复制,如果 from 区中对象复制次数达到阈
值,就直接复制到老年代。

老年代回收
进入老年代的数据较少,所以老年代区被占满的速度较慢,所以垃圾回收也不频繁。老年代
GC 称为 Old GCMajor GC。由于老年代对象一般来说存活次数较长,所有较常采用
标记-压缩算法。

Full GC
对所有"代"的内存进行垃圾回收

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

GC 触发条件
Minor GC 触发条件:当 eden 区满了触发
Full GC 触发条件: 老年代满了,新生代搬向老年代,老年代空间不够,持久代满了
使用 System.gc()手动调用,不推荐
GC 调整策略
减少 STW 时长,串行变并行
减少 GC 次数,要分配合适的内存大小
对 JVM 调整策略应用极广
在 WEB 领域中 Tomcat 等
在大数据领域 Hadoop 生态各组件
在消息中间件领域的 Kafka 等
在搜索引擎领域的 ElasticSearch、Solr 等

在不同领域对 JVM 需要不同的调整策略

四.Tomcat 中 JVM 配置

最常见的 JVM 配置当属内存分配,因为在绝大多数情况下, JVM 默认分配的内存可能不能够
满足我们的需求。特别是在生产环境,此时需要手动修改 Tomcat 启动时的内存参数分配。

linux 平台(catalina.sh) :

JAVA_OPTS="-server -Xms1024m -Xmx2048m -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m -XX:SurvivorRatio=8"

windows 平台(catalina.bat) :

set JAVA_OPTS=-server -Xms2048m -Xmx2048m -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=256m -XX:SurvivorRatio=8

选项说明

参数 说明 举例
-Xms 设置应用程序初始使用的堆内存大小(新生代+老年代) -Xms2g
-Xmx 设置应用程序能获得的最大堆内存,早期 JVM 不建议超过 32G,内存管理效率下降 -Xms4g
-XX:NewSize 设置初始新生代大小
-XX:MaxNewSize 设置最大新生代内存空间
-XX:NewRatio 以比例方式设置新生代和老年代 -XX:NewRatio=2 new/old=1/2
-XX:SurvivorRatio 以比例方式设置 eden 和 survivor -XX:SurvivorRatio=6 eden/survivor=6/1 survivor/new=1/8 如-XX:SurvivorRatio=10 表示伊甸园区(Eden) 是幸存区 To 大小的 10 倍(也是幸存区 From 的 10 倍)。所以,伊甸园区(Eden) 占新生代大小的 10/12 ,幸存区 Frcm 和幸存区 To 每个占新生代的 1/12 。注意,两个幸存区永远是一样大的。
-Xss 设置线程的栈大小
-XX:Metaspacesize 元空间内存初始大小,在 JDR1. 8 版本之前配置为-Xx:Permsize (永久代)
-XX:MaxMetaspacesize 元空间内存最大大小,在 JDK1. 8 版本之前配置为-XX:MaxPermsize (永久代)
-XX:ReservedCodeCacheSize -XX: InitialCodeCachesize 代码缓存区大小
-XX:NewRatio 设置新生代和老年代的相对大小比例。这种方式的优点是新生代大小会随着整个堆大小动态扩展。如-XX:NewRatio=3 指定老年代/新生代为 3/1。老年代占堆大
小的 3/4,新生代占 1/4。

配置选项与堆内存的对应关系

Reference

1.Garbage Collection: How it’s done----by Kasun Dharmadasa

发布了108 篇原创文章 · 获赞 58 · 访问量 1万+

Guess you like

Origin blog.csdn.net/YouOops/article/details/104110523