JVM虚拟机将其内存数据分为程序计数器、虚拟机栈、本地方法栈、Java堆和方法区这五个部分。我们可以将上述几个区域分为线程共享和线程私有两大类。
线程共享指的是可以允许被所有的线程共享访问的一类内存区,随虚拟机的启动而创建,关闭而销毁。这类区域包括堆内存区、方法区、运行时常量池三个内存区。 线程私有区域指的是线程独有的区域,随线程的结束而销毁。这个区域包括程序计数器、本地方法区、虚拟机栈等。
程序计数器
存在寄存器中
为什么有计数器? 处理器要执行的程序(指令序列)都是以二进制代码序列方式预存储在计算机的存储器中,处理器将这些代码逐条地取到处理器中再译码、执行,以完成整个程序的执行。为了保证程序能够连续地执行下去,CPU必须具有某些手段来确定下一条取址指令的地址,程序计数器正是起到这种作用,所以通常又称之为“指令计数器”。
程序计数器用于存储当前运行的线程所执行的字节码的行号执行器,即下一条运行的指令,无内存溢出问题。
方法区
方法区用于存放程序的类元数据信息,在 Java 中本地方法区相当于 Native 方法。存放的是常量(静态变量和类信息、如类的版本、字段、方法、接口描述等)、即时编译后代码、运行时常量池。
栈
存在通用RAM中
为什么需要栈? 由于Java编译器需要预先去生成相应的内存空间,所以当我们尝试创建程序的时候,Java编译器必须知道被存储在栈内的所有数据的确切大小和生命周期,以便可以通过上下移动堆栈指针来动态调整内存空间。
虚拟机栈和本地方法栈用于存放函数调用堆栈信息,虚拟机栈是描述 Java 方法的执行过程的内存模型,局部变量表、操作数栈、动态链接、方法的返回值和异常分派栈帧用来记录方法的执行过程。
堆
Java堆用于存放Java程序运行时所需的对象等数据,堆是一个运行时数据区,类的对象从中分配空间。这些对象通过New关键字被建立,它们不需要程序代码来显式地释放。
堆是由垃圾回收来负责的,堆的优势是可以动态地分配内存大小,生存周期也不需要事先告诉编译器。
总结
JVM 性能调优主要是对方法区、堆、栈的调优,方法如下:
- 可以通过调整JVM参数来优化JVM的性能,如设置堆内存大小、垃圾回收器类型、线程数等。
- 优化代码可以减少JVM的负担,如避免使用大量的循环、减少对象的创建等。
- 缓存可以减少JVM对外部资源的访问,提高程序的效率。
- 使用并发编程可以充分利用多核CPU的性能,提高程序的效率。
在调优前如果不知道 JVM 的性能瓶颈可以使用JVM工具来分析程序的性能瓶颈,如Java VisualVM、JConsole等。