Java JVM虚拟机(一)

本文详细解析JVM工作原理,涵盖字节码加载、执行引擎、数据区划分等关键概念,揭示JVM与Java语言的关系及对象内存分配细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

1.JVM虚拟机中运行的是class字节码文件,我们编写的 .java源码文件需要java编译器编译成.class文件才能在JVM虚拟机中运行

   在黑窗口中输入的 javac  ###.java  命令就是将###.java文件编译成字节码文件.

 

2.可以更进一步的理解,不管是哪种语言编写的字节码文件,只要是一个合法的符合要求的字节码文件,JVM都会跑起来,所以JVM并不是我们想象的只与java语言紧紧的捆绑在一起.就是因为有Java虚拟机(JVM)的存在,java才实现了程序与操作系统的分离.

 

3.JVM的生命周期

JVM虚拟机有着一个明确的生命周期,java程序开始运行,JVM启动,java程序结束运行,JVM关闭.

任何一个拥有public static void main(String[] args)函数的class都可以作为JVM实例运行的起点

main()作为该程序初始线程的起点,任何其他线程均由该线程启动。JVM内部有两种线程:守护线程和非守护线程,main()属于非守护线程,守护线程通常由JVM自己使用,java程序也可以标明自己创建的线程是守护线程

当程序中的所有非守护线程都终止时,JVM才退出;若安全管理器允许,程序也可以使用Runtime类或者System.exit()来退出

 

4.JVM的运行数据区划分

栈:运行时的单位,解决程序的运行问题,即程序如何运行,如何处理数据

堆:储存的单位,解决数据储存的问题,数据怎么放 放在哪

方法区:java的字节码文件会加载到方法区中

本地方法栈:此区是java语言调用操作系统有关方法的地方

PC寄存器:此区是与操作CPU有关的地方

5.在java中,参数传递是值的传递还是引用的传递呢?

基本类型作为参数传递时,是传递值的拷贝,无论你怎么改变这个拷贝,原值是不会改变的

对象作为参数传递时,是把对象在内存中的地址拷贝了一份传给了参数

6.java对象的大小

基本数据类型的大小是固定的

空Object的大小是8byte

      Object o = new Object();

     它所占用的空间为:4byte(栈) + 8byte(堆)

Class Dog {

    int count;

    boolean flag;

    Object ob;

}

其大小为:空对象大小(8byte)+int大小(4byte)+Boolean大小(1byte)+空Object引用的大小(4byte)=17byte

但是因为Java在对对象内存分配时都是以8的整数倍来分,因此大于17byte的最接近8的整数倍的是24,因此此对象的大小为24byte

7.JVM实例和JVM执行引擎实例

      JVM实例对应了一个独立运行的java程序,它是进程级别.

      JVM执行引擎实例对应了java运行程序中的线程,它属于线程级别

8.JVM内部体系中的三部分

      1).类装载器(ClassLoader)子系统

         作用:用来装载.class文件

      2).执行引擎

         作用:执行字节码或者执行本地方法

      3).运行时数据区

         方法区  堆  栈  PC寄存器  本地方法栈

这里写一个简单的ClassLoader例子

自定义一个MyClassLoader继承ClassLoader抽象类,

public class MyClassLoader extends ClassLoader{

	//重写ClassLoader中的findClass方法,将一个字节数组转化为Class类的实例
	@Override
	protected Class<?> findClass(String name) throws ClassNotFoundException {
		byte[] bs = null;
		
		try {
			bs = loadClassData(name);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		
		return defineClass("classloader_demo.TestClass", bs, 0,bs.length);//从byte[]数组中还原出一个Class对象
	}
	
	//将给定路径的.class文件转换为字节数组
	private byte[] loadClassData(String filepath) throws Exception {
		int n = 0;
		
		BufferedInputStream bInputStream = 
				new BufferedInputStream(new FileInputStream(new File(filepath)));
		
		//创建一个字节数组缓冲区来接收读取到的字节
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		
		while((n = bInputStream.read()) != -1) {
			bos.write(n);
		}
		bInputStream.close();
		bos.close();
		return bos.toByteArray();
	}
	
}

自定义类

public class TestClass {

	int age;
	String name;
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	
}

测试类

public class Test {

	public static void main(String[] args) throws Exception {

		MyClassLoader mLoader = new MyClassLoader();
		Class c = mLoader.findClass("C:\\Users\\admin\\Desktop\\TestClass.class");
		
		Object object = c.newInstance();
		Method[] methods = c.getMethods();
		for (Method method : methods) {
			System.out.println(method.getName());
		}
	};

}

这里首先将TestClass.java文件转化为TestClass.class文件,将字节码文件转换为字节数组,再把字节数组转换为类文件,最后使用反射读取类文件中的所有公共方法,图中就看到输出的log信息啦!

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值