JVM调优:基本概念

作者:和你在一起
来源:https://www.iteye.com/blog/pengjiaheng-518623
 
一. JVM的运行数据区
 
首先我简单来画一张 JVM的结构原理图,如下 。
JVM调优:基本概念

文章插图
 
我们重点关注 JVM在运行时的数据区,你可以看到在程序运行时,大致有5个部分 。
1.方法区
不止是存“方法”,而是存储整个 class文件的信息,JVM运行时,类加载器子系统将会提取 class文件里面的类信息,并将其存放在方法区中 。例如类的名称、类的类型(枚举、类、接口)、字段、方法等等 。
2.堆( Heap)
熟习 c/c++编程的同学们应该相当熟习 Heap了,而对于JAVA而言,每个应用都唯一对应一个JVM实例,而每一个JVM实例唯一对应一个堆 。堆主要包括关键字 new的对象实例、 this指针,或者者数组都放在堆中,并由应用所有的线程共享 。堆由JVM的自动内存管理机制所管理,名为垃圾回收—— GC(garbage collection) 。
3.栈( Stack)
操作系统内核为某个进程或者者线程建立的存储区域,它保存着一个线程中的方法的调用状态,它具备先进后出的特性 。在栈中的数据大小与生命周期严格来说都是确定的,例如在一个函数中公告的int变量便是存储在 stack中,它的大小是固定的,在函数退出后它的生命周期也从此结束 。在栈中,每一个方法对应一个栈帧,JVM会对Java栈执行两种操作:压栈和出栈 。这两种操作在执行时都是以栈帧为单位的 。还有少量即时编译器编译后的代码等数据 。
4.PC寄存器
pc寄存器用于存放一条指令的地址,每一个线程都有一个PC寄存器 。
5.本地方法栈
用来调用其余语言的本地方法,例如 C/C++写的本地代码, 这些方法在本地方法栈中执行,而不会在Java栈中执行 。
 
二. 数据类型
 
Java虚拟机中,数据类型可以分为两类:基本类型和引用类型 。
 
  • 基本类型的变量保存原始值,即:他代表的值就是数值本身;
  • 而引用类型的变量保存引用值 。“引用值”代表了某个对象的引用,而不是对象本身,对象本身存放在这个引用值所表示的地址的位置 。
  • 基本类型包括:byte,short,int,long,char,float,double,Boolean,returnAddress 。
  • 引用类型包括:类类型,接口类型和数组 。
 
三. 堆与栈
 
堆和栈是程序运行的关键,很有必要把他们的关系说清楚 。
 
JVM调优:基本概念

文章插图
 
 
栈是运行时的单位,而堆是存储的单位 。 
栈解决程序的运行问题,即程序如何执行,或者说如何处理数据;堆解决的是数据存储的问题,即数据怎么放、放在哪儿 。
 
在Java中一个线程就会相应有一个线程栈与之对应,这点很容易理解,因为不同的线程执行逻辑有所不同,因此需要一个独立的线程栈 。而堆则是所有线程共享的 。
 
栈因为是运行单位,因此里面存储的信息都是跟当前线程(或程序)相关信息的 。包括局部变量、程序运行状态、方法返回值等等;而堆只负责存储对象信息 。
 
为什么要把堆和栈区分出来呢?栈中不是也可以存储数据吗? 
第一,从软件设计的角度看,栈代表了处理逻辑,而堆代表了数据 。这样分开,使得处理逻辑更为清晰 。分而治之的思想 。这种隔离、模块化的思想在软件设计的方方面面都有体现 。
 
第二,堆与栈的分离,使得堆中的内容可以被多个栈共享(也可以理解为多个线程访问同一个对象) 。这种共享的收益是很多的 。一方面这种共享提供了一种有效的数据交互方式(如:共享内存),另一方面,堆中的共享常量和缓存可以被所有栈访问,节省了空间 。
 
第三,栈因为运行时的需要,比如保存系统运行的上下文,需要进行地址段的划分 。由于栈只能向上增长,因此就会限制住栈存储内容的能力 。而堆不同,堆中的对象是可以根据需要动态增长的,因此栈和堆的拆分,使得动态增长成为可能,相应栈中只需记录堆中的一个地址即可 。
 
第四,面向对象就是堆和栈的完美结合 。其实,面向对象方式的程序与以前结构化的程序在执行上没有任何区别 。但是,面向对象的引入,使得对待问题的思考方式发生了改变,而更接近于自然方式的思考 。当我们把对象拆开,你会发现,对象的属性其实就是数据,存放在堆中;而对象的行为(方法),就是运行逻辑,放在栈中 。我们在编写对象的时候,其实即编写了数据结构,也编写的处理数据的逻辑 。不得不承认,面向对象的设计,确实很美 。


推荐阅读