JVM

JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。JVM包括一套字节码指令集、一组寄存器、一个栈、一个垃圾回收堆和一个存储方法域。 JVM屏蔽了与具体操作系统平台相关的信息,使Java程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。JVM在执行字节码时,实际上最终还是把字节码解释成具体平台上的机器指令执行。

JVM架构图

JVM的核心是由类加载器(Class Loader)、执行引擎(Execute Engine)和Java Memory Management(JVM内存管理器)共同组成

  • JVM管理(JVM Memory Management)的内存段可分为两大类:线程共享内存和线程私有内存

    • 程序计数寄存器(Program Counter Register): 每个线程有自己的计数寄存器,存储当前线程执行字节码的地址

    • jvm栈(JVM Stack): jvm会为每个运行线程分配一个栈区,线程调用方法时和方法返回时会进行入栈和出栈操作

    • 本地方法栈区(Native Stack): 与jvm stack类似,只不过此区域是为调用本地方法服务(系统调用)

    • 方法区(Method Area): 存储jvm加载的class、常量、静态变量、即时编译器编译后的代码等

    • java堆(Java Heap): 存储java的所有对象实例、数组等

    • 线程共享内存

    • 线程私有内存

Java Heap架构

在Java世界中使用内存不需要程序员手动申请,只需定义变量,由JVM自动为其分配相应的内存,GC负责内存垃圾回收。

  • 年轻代(Young Generation): 也叫Survivor Generation

    • eden: 存放新创建的对象。

    • to|from: 存放年轻代执行minor GC后存活下来的对象

  • 老年代(Old Generation): 存放多次年轻代执行minor GC后存活下来的对象

  • 持久代(Permanent Generation): 存放java class类和meta数据


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

# 分配了一个又一个对象

放到Eden

# 不好,Eden区满了,只能GC(新生代GC:Minor GC)了

Eden区的存活对象copyfrom区,然后清空Eden区(本来to区也需要清空的,不过本来就是空的)

# 又分配了一个又一个对象

放到Eden

# 不好,Eden区又满了,只能GC(新生代GC:Minor GC)了

Eden区和from区的存活对象copyto区,然后清空Eden区和from

# 又分配了一个又一个对象

放到Eden

# 不好,Eden区又满了,只能GC(新生代GC:Minor GC)了

Eden区和to区的存活对象copyfrom区,然后清空Eden区和to

# ...

# 有的对象来回在Survivor区呆了比如15次,就被分配到老年代Old区

# 有的对象太大,超过了Eden区,直接被分配在Old区

# 有的存活对象,放不下Survivor区,也被分配到Old区

# ...

# 在某次Minor GC的过程中突然发现:

# 不好,老年代Old区也满了,这是一次大GC(老年代GC:Major GC)

Old区慢慢的整理一番,空间又够了

# 继续Minor GC

# ...

 


tomcat常用的优化配置
  • 优化tomcat进程使用的Java Heap内存空间


1

2

3

4

5

6

7

8

9

10

# 修改catalina.sh文件中的JAVA_OPTS

JAVA_OPTS="-server -Xms512m -Xmx512m -XX:NewSize= -XX:MaxNewSize= -XX:PermSize= -XX:MaxPermSize="

  -server  # 服务器模型

  -Xms  # 堆内存初始化大小

  -Xmx  # 堆内存空间上限

  -XX:NewSize=  # 新生代空间初始化大小

  -XX:MaxNewSize=  # 新生代空间最大值

  -XX:PermSize=  # 持久代空间初始化大小

  -XX:MaxPermSize=  # 持久代空间最大值

 


  • 线程池设置:


1

2

3

4

5

6

7

8

9

10

11

12

13

14

# 修改server.xml文件

<Connector port="8080" protocol="HTTP/1.1"  connectionTimeout="20000" redirectPort="8443"

    maxThreads=  # 最大线程数

    minSpareThreads=  # 最小空闲线程数

    maxSpareThreads=  # 最大空闲线程数

    acceptCount=  # 等待队列的最大长度

    URIEncoding=  # URI地址编码格式,建议使用UTF-8

    enableLookups=  # 是否启用dns解析,建议禁用

    compression=  # 是否启用传输压缩机制,建议“on"

    compressionMinSize=  # 启用压缩传输的数据流最小值,单位是字节

    compressableMimeType=  # 定义启用压缩功能的MIME类型。如text/html, text/xml, text/css, text/javascript

    Server=  # 修改tomcat版本信息

/>

 


  • 禁用8005端口


1

2

3

# 修改server.xml文件

<Server port="-1" shutdown="SHUTDOWN">

 


JVM常用的分析工具

  • jps: 用来查看运行的所有jvm进程


1

2

3

4

5

6

7

8

jps [-q] [-mlvV] [<hostid>]

-q:静默模式

-v:显示传递给jvm的命令行参数

-m:输出传入main方法的参

-l:输出main类或jar完全限定名称

-V:显示通过flag文件传递给jvm的参数

[<hostid>]:主机id,默认为localhost

 


  • jinfo: 查看进程的运行环境参数,主要是jvm命令行参数


1

2

3

4

5

jinfo [option] <pid>

-flagsto print VM flags

-syspropsto print Java system properties

-flag <name>to print the value of the named VM flag

 


  • jstat: 对jvm应用程序的资源和性能进行实时监控


1

2

3

4

5

jstat -help|-options

jstat -<option> [-t] [-h<lines>] <vmid> [<interval> [<count>]]

 

常见用法 jstat -gc PID

 


  • jstack: 查看所有线程的运行状态


1

2

3

4

5

6

jstack [-l] <pid>

jstack -F [-m] [-l] <pid>

    -llong listings,会显示额外的锁信息,因此,发生死锁时常用此选项

    -m:混合模式,既输出java堆栈信息,也输出C/C++堆栈信息

    -F:当使用“jstack -l PID"无响应,可以使用-F强制输出信息

 


  • jmap: 查看jvm占用物理内存的状态

  • jconsole:JVM内存图形化监控工具

  • jvisualvm:JVM内存图形化监控工具