这个九月份一直没有更博,因为换了工作大部分时间都在熟悉新业务和python上,今天来更新下,最近上下班及业余时间看jvm比较多,特来总结下自己在jvm方面的心得。
javaer去一家新公司常常会安装本地java开发环境,首下载的就是jdk了,jdk是个啥子哦,这里可以拆分下:
jdk:
一些工具tool
jre:
jvm
常用的lib类库
所以我们经常会将环境变量的path 添加一下jdk和jre,目的就是让本地写的java代码可以被compiler编译和在jvm上运行
ok,接下来就是说一说jvm了,java virtual machine,我的理解是可以执行.class的程序。很肤浅的理解,是的,在这方面我也是小白,需要不断加深学习的。
说到jvm的结构,一般是其在内存上创建的结构,因为内存要临时存储.class相关数据。在内存上的区域分为:
1、堆heap:jvm内存上最大的一块,用来存储创建的java对象,线程共享,GC频繁区
2、堆栈或者栈stack:通过入栈和出栈代表运行时的方法调用和结束,还会临时存储对象的引用reference和基本数据类型,因为一个方法的调用必然会涉及到对象的调用(并不直接操作对象,而是通过reference),线程私有,不需要GC,生命周期和线程同步
3、方法区:存放一些类信息,类的静态变量,常量及方法。一个类初次加载时会加载这些信息到方法区。线程共享,GC几乎不在该区工作
4、程序计数器:当cpu切换上下文时当前运行的线程在退出cpu前将运行的状态保存在这里,下次继续运行时从保存状态开始。因此这一块是线程私有的。GC不在此工作
好了,上边的内容做了各区域的单方面介绍,那么当一个类被加载并且运行其中某一个方法并得到运行结果是怎么一个过程呢?
ok,假如小明要跑一个java程序,这里简单写一个这个程序(最近写python这种语言,简单的语法结构差点让我忘记了java的严谨…………):
public HelloWorld {
public HelloWorld(String name) {
this.name = name;
}
private string name;
private static String str = "Hello World! I m";
public void sayHello(String name) {
System.out.println(str + name);
}
public static void main(String[] args) {
HelloWorld hw = new HelloWorld;
hw.sayHello();
}
}
javac HelloWorld
java HelloWorld("fujian")
result: Hello World! I m fujian
ok,上边这个类是如何在jvm里转了一圈儿运行出输出结果的呢?
首先这个HelloWorld的java文件被编译成class文件,这样就能被jvm识别和加载了,当初次加载时这个HelloWorld.class的类信息和 静态变量’Hello World! I m’ 还有 sayHello方法 和 main方法 被加载到内存方法区。
然后以main为执行入口,new一个HelloWorld对象,这个对象new的过程就是:
先初始化全局变量,name初始化为null(name这个引用在栈上),str(栈上)本来就指向方法区内的‘Hello World! I m’; 然后调用构造函数(),将‘fujian’这个string值(除了String类型的值应该在堆上,但string比较特殊,在方法区)关联到name(引用在栈上),构造结束();
new出的HelloWorld对象在堆上。并且有个引用hw(栈上)关联到这个对象,调用对象的sayHello()方法,方法开始(入栈),将引用指向的值通过组合运算并输出。方法结束(出栈)。此时以上栈中的引用随着方法的结束而消失。new的对象在随后的GC中因为没有引用指向它而被垃圾回收。
上边其实讲的很粗糙,因为我的理解可能也比较肤浅。日后随着理解正确性的提升再更新吧。刚刚提到了GC,有时间也总结下GC的算法和具体实现。