JVM的一些概念
背景:之前我们的项目是部署在阿里云上,运行容器使用的是tomcat,因为是创业公司,所以以前写的代码都是为了完成业务逻辑,对于代码结构,代码质量甚至部分安全性都没有好的保障这就导致了我们的服务经常会报警说内存不够。当时为了解决问题,就对我们项目的jvm参数进行了一些调优,但是当时感觉对JVM还是不是很了解,所以最近就看了些资料,以下是我对JVM的一些了解。
一:什么是JVM?
JVM就是java虚拟机。JVM是JRE的一部分。它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。JVM有自己完善的硬件架构,如处理器、堆栈、寄存器等,还具有相应的指令系统。
二:什么是JRE?
JRE即Java Runtime Enviroment,是java运行环境英文的缩写。我们的写的代码,编译好了之后就是.class文件,该文件依赖于JRE运行,也就成为我们说的java服务了。JRE中包含了JVM以及JAVA程序运行时所需的核心类库。
三:什么是JDK?
JDK就是Java Development ToolKit的缩写,中文意思就是java开发工具。JDK中包含了很多我们平时java开发中需要用到的java函数库,当然,jdk中也包含我们的java运行环境jre。即JDK包含JRE,而JRE又包含JVM。
四:字节码,虚拟机之间的关系。
如上图我们可以看出,首先我们是通过javac.exe程序将java文件编译成.class文件,然后通过类加载器将数据加载到java内存中去。那么,我们的方法区,堆,栈,都存储那些信息呢?
这里我们给出一个java类用于举例子:
package com.ruoyi.system.test.domain;
/**
* @author xiebiao
* @version V1.0
* @Title:
* @Package
* @Description: 用于测试JVM
* @date
*/
public class Order {
/**
* 产品名称
*/
private String productName;
/**
* 价格
*/
private Double price;
/**
* 产品编号
*/
private String getProductId;
/**
* 随机折扣
*/
private static Double randomDiscount;
public String getProductName() {
return productName;
}
public void setProductName(String productName) {
this.productName = productName;
}
public String getGetProductId() {
return getProductId;
}
public void setGetProductId(String getProductId) {
this.getProductId = getProductId;
}
/**
* 随机给价格打折。
* @return
*/
public Double getPrice() {
randomDiscount = Math.random ();
return price!=null?price*randomDiscount:price;
}
public void setPrice(Double price) {
this.price = price;
}
}
1:方法区:当虚拟机装载某个类时,比如是Order.class订单类,会读入该类对应的字节码文件到虚拟机JVM中,随后JVM会读取到这个类的相关信息。并将信息分类储存。
- 该类的全类名,比如com.ruoyi.system.test.domain.Order;
- 这个类的访问修饰符,比如该类是public还是default等等。
- 该类的一些字段信息:比如修饰符,类型,字段名(private String productName;)以及方法信息:方法名,返回类型,参数数量和类型,修饰符(public void setProductName(String productName)...)
- 除了常量以外的所有类的静态变量:private static Double randomDiscount
- 常量池:比如我们声明一个变量int i = 1;那么这个i就是变量,在堆中,i此时是个对象,而1是常量,在常量池中。又或者我们声明了一个变量,public static final string CHANG_LIANG = "常量";其中“常量”本身是个变量,现在它变成了常量,存放在常量池中,而CHANG_LIANG仍然是个对象,存放在堆中。
public static void main(String[] args) {
Order order = new Order ();
}
2:堆区
堆和栈,大家一直傻傻分不清楚,最近网上有句挺火的话,不要在垃圾堆里面找对象。所以我们只需要记住,堆里面是放对象的就行。比如此时我在main函数中new了一个Order对象,那么,此时我们就在堆中开辟了一块地址,假如地址编号是437300(老家的邮编),该块地址里面存储的是该对象的信息,比如产品名称和价格等。
3:栈区
3.1、当我们启动一个线程时,JVM就会为该线程分配一个JAVA栈,该线程会调用多个方法。而这些方法的调用状态,包括局部变量,参数,返回值等都会保存在栈内存中。而我们上面的代码中,当启动main方法时,会在栈中开辟一款内存名叫order,其中存着指向Order对象的地址437300.
3.2、栈由许多栈帧组成,一个栈帧包含一个JAVA方法调用的状态,当线程调用一个方法时,JVM压入(push)一个新的栈帧到该线程的java栈中,当该方法返回时,这个栈帧就从java栈中弹出(pop)
当线程在运行时,假如调用method1,method1又调用了method2,method3,method2又调用了method4.那么在调用methood1时,就会将该栈帧压入到相应的栈中去,当运行到method2时,又push方法method2,然后push方法method3,方法method3执行完了之后,java栈中则pop(弹出)method3,然后将method4push到栈中去,method4执行完了之后则相继popmethod4,method2,method1.
下一篇将描述我对于堆的一些理解。以及JVM调优,究竟调的是那些数据,新生代老年代伊甸园区的一些认识。